implemented a mechanism in mapnik2._injector to be able to override c++ methods (at the python layer only). Used it to implement a friendlier constructor for Feature and a add_geometry() method that accepts shapely.geometry.Geometrys, and wkb/wkt strings

This commit is contained in:
Alberto Valverde 2010-03-19 18:14:46 +00:00
parent a613dc6397
commit 18b811d19d
2 changed files with 72 additions and 12 deletions

View File

@ -63,6 +63,8 @@ class _injector(object):
for b in bases:
if type(b) not in (self, type):
for k,v in dict.items():
if hasattr(b, k):
setattr(b, '_c_'+k, getattr(b, k))
setattr(b,k,v)
return type.__init__(self, name, bases, dict)
@ -250,15 +252,56 @@ class _DeprecatedFeatureProperties(object):
"feature object itself for the same effect", DeprecationWarning, 2)
return iter(self._feature)
class _Feature(Feature,_injector):
class _Feature(Feature, _injector):
"""
A Feature.
TODO: docs
"""
@property
def properties(self):
return _DeprecatedFeatureProperties(self)
@property
def attributes(self):
#XXX Returns a copy! changes to it won't affect feat.'s attrs.
# maybe deprecate?
return dict(self)
@property
def geometry(self):
if self.num_geometries() > 0:
return self.get_geometry(0)
@property
def geometries(self):
return [self.get_geometry(i) for i in xrange(self.num_geometries())]
def __init__(self, id, geometry=None, **properties):
Feature._c___init__(self, id)
if geometry is not None:
self.add_geometry(geometry)
for k, v in properties.iteritems():
self[k] = v
def add_geometry(self, geometry):
geometry = self._as_wkb(geometry)
Feature._c_add_geometry(self, geometry)
def _as_wkb(self, geometry):
if hasattr(geometry, 'wkb'):
# a shapely.geometry.Geometry
geometry = geometry.wkb
if isinstance(geometry, str):
# ignoring unicode un purpose
for type_ in ('POINT', 'POLYGON', 'LINE'):
if type_ in geometry:
# A WKT encoded string
from shapely import wkt
geometry = wkt.loads(geometry).wkb
return geometry
raise TypeError("%r (%s) not supported" % (geometry, type(geometry)))
class _Symbolizer(Symbolizer,_injector):
def symbol(self):
return getattr(self,self.type())()

View File

@ -13,6 +13,18 @@ class FeatureTest(unittest.TestCase):
f = self.makeOne(1)
self.failUnless(f is not None)
def test_python_extended_constructor(self):
try:
from shapely.geometry import Point
except ImportError:
raise Todo("Make this test not dependant on shapely")
f = self.makeOne(1, Point(3,6), foo="bar")
self.failUnlessEqual(f['foo'], 'bar')
env = f.geometry.envelope()
self.failUnlessEqual(env.minx, 3)
self.failUnlessEqual(env.miny, 6)
def test_set_get_properties(self):
f = self.makeOne(1)
counter = itertools.count(0)
@ -26,19 +38,24 @@ class FeatureTest(unittest.TestCase):
for v in (1, True, 1.4, "foo", u"avión"):
test_val(v)
def test_add_wkb_geometry_(self):
def test_add_wkb_geometry(self):
try:
from shapely.geometry import Point
except ImportError:
raise Todo("Make this test not dependant on shapely")
f = self.makeOne(1)
self.failUnlessEqual(f.num_geometries(), 0)
f.add_geometry(Point(3,6).wkb)
self.failUnlessEqual(f.num_geometries(), 1)
geom = f.get_geometry(0)
env = geom.envelope()
self.failUnlessEqual(env.minx, 3)
self.failUnlessEqual(env.minx, env.maxx)
self.failUnlessEqual(env.miny, 6)
self.failUnlessEqual(env.miny, env.maxy)
def add_it(geometry):
f = self.makeOne(1)
self.failUnlessEqual(len(f.geometries), 0)
f.add_geometry(geometry)
self.failUnlessEqual(len(f.geometries), 1)
env = f.geometry.envelope()
self.failUnlessEqual(env.minx, 3)
self.failUnlessEqual(env.minx, env.maxx)
self.failUnlessEqual(env.miny, 6)
self.failUnlessEqual(env.miny, env.maxy)
geometries = (Point(3,6), 'POINT(3 6)', Point(3,6).wkb)
for geom in geometries:
add_it(geom)