Skip to content

Commit

Permalink
prevents issue where layer name matches a column name
Browse files Browse the repository at this point in the history
  • Loading branch information
fitnr committed Mar 9, 2016
1 parent 054c25b commit 2ff8c83
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 29 deletions.
6 changes: 2 additions & 4 deletions svgis/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,10 @@ def construct_classes(classes, properties):
properties (dict): A single feature's properties.
Returns:
str (unicode in Python 2)
(list) class names
'''
f = u'{}_{}'
classed = (f.format(p, properties[p]) if p in properties else p for p in classes)
sanitized = (sanitize(w) for w in classed)
return u' '.join(sanitized)
return [sanitize(f.format(p, properties.get(p))) for p in classes if p in properties]


def pick(style):
Expand Down
27 changes: 15 additions & 12 deletions svgis/svgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,17 +266,14 @@ def _prepare_layer(self, layer, filename, bounds, scalar, **kwargs):

# Correct for OGR's lack of creativity for GeoJSONs.
if layer.name == 'OGRGeoJSON':
result['layer'] = os.path.splitext(os.path.basename(filename))[0]
result['name'] = os.path.splitext(os.path.basename(filename))[0]
else:
result['layer'] = layer.name
result['name'] = layer.name

# A list of class names to get from layer properties.
class_fields = kwargs.pop('class_fields', None) or self.class_fields
result['classes'] = [x for x in class_fields if x in layer.schema['properties']]

# Add the layer name to the class list.
result['classes'].insert(0, result['layer'])

# Remove the id field if it doesn't appear in the properties.
id_field = kwargs.pop('id_field', self.id_field)

Expand Down Expand Up @@ -339,7 +336,7 @@ def _compose_file(self, filename, unprojected_bounds=None, padding=None, **kwarg

return {
'members': group,
'id': kwargs['layer'],
'id': kwargs['name'],
'class': u' '.join(_style.sanitize(c) for c in layer.schema['properties'].keys())
}

Expand All @@ -353,21 +350,27 @@ def _feature(self, feature, transforms, classes, id_field=None, **kwargs):
classes (list): Names (unsanitized) of fields to apply as classes in the output element.
id_field (str): Field to use as id of the output element.
kwargs: Additional properties to apply to the element.
name (str): layer name (usually basename of the input file).
Returns:
unicode
'''
layer = kwargs.pop('layer', '?')
name = kwargs.pop('name', '?')

# Set up the element's properties.
kwargs['class'] = _style.construct_classes(classes, feature['properties'])
classes = _style.construct_classes(classes, feature['properties'])
# Add the layer name to the class list.
if name != '?':
classes.insert(0, _style.sanitize(name))
kwargs['class'] = ' '.join(classes)

if id_field:
kwargs['id'] = _style.sanitize(feature['properties'].get(id_field))

try:
# Check if geometry exists (a bit unpythonic, but cleaner errs this way).
geom = feature['geometry']

# Check if geometry exists (a bit unpythonic, but cleaner errs this way).
if geom is None:
raise KeyError('NULL geometry')

Expand All @@ -378,12 +381,12 @@ def _feature(self, feature, transforms, classes, id_field=None, **kwargs):

except KeyError as e:
self.log.warning('no geometry found for feature %s of %s: %s',
kwargs.get('id', feature.get('id', '?')), layer, e)
kwargs.get('id', feature.get('id', '?')), name, e)
return u''

except ValueError as e:
self.log.warning('error transforming feature %s of %s: %s',
kwargs.get('id', feature.get('id', '?')), layer, e)
kwargs.get('id', feature.get('id', '?')), name, e)
return u''

try:
Expand All @@ -392,7 +395,7 @@ def _feature(self, feature, transforms, classes, id_field=None, **kwargs):

except (TypeError, errors.SvgisError) as e:
self.log.warning('unable to draw feature %s of %s: %s',
kwargs.get('id', feature.get('id', '?')), layer, e)
kwargs.get('id', feature.get('id', '?')), name, e)
return u''

def compose(self, scalar=None, bounds=None, **kwargs):
Expand Down
18 changes: 9 additions & 9 deletions tests/test_style.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,30 +159,30 @@ def testSanitize(self):
self.assertEqual(style.sanitize(u'"huh"'), u'huh')

def testConstructClasses(self):
self.assertEqual(style.construct_classes(('foo',), {'foo': 'bar'}), 'foo_bar')
self.assertEqual(style.construct_classes(['foo'], {'foo': 'bar'}), 'foo_bar')
self.assertEqual(style.construct_classes(('foo',), {'foo': 'bar'}), [u'foo_bar'])
self.assertEqual(style.construct_classes(['foo'], {'foo': 'bar'}), [u'foo_bar'])

self.assertEqual(style.construct_classes(['foo'], {'foo': None}), 'foo_None')
self.assertEqual(style.construct_classes(['foo'], {'foo': None}), [u'foo_None'])

def testCreateClasses(self):
classes = style.construct_classes(self.classes, self.properties)
self.assertEqual(classes, u'apple_fruit potato')
self.assertEqual(classes, [u'apple_fruit'])

classes = style.construct_classes(self.classes, {'apple': u'fruit'})
self.assertEqual(classes, u'apple_fruit potato')
self.assertEqual(classes, [u'apple_fruit'])

classes = style.construct_classes(self.classes, {'apple': u'früit'})
self.assertEqual(classes, u'apple_früit potato')
self.assertEqual(classes, [u'apple_früit'])

classes = style.construct_classes(self.classes, {'apple': 1})
self.assertEqual(classes, u'apple_1 potato')
self.assertEqual(classes, [u'apple_1'])

def testCreateClassesMissing(self):
classes = style.construct_classes(self.classes, {'apple': ''})
self.assertEqual(classes, 'apple_ potato')
self.assertEqual(classes, [u'apple_'])

classes = style.construct_classes(self.classes, {'apple': None})
self.assertEqual(classes, 'apple_None potato')
self.assertEqual(classes, [u'apple_None'])

def testCDATA(self):

Expand Down
11 changes: 7 additions & 4 deletions tests/test_svgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,14 @@ def testDrawGeometry(self):
'cat': 'meow'
}
}
drawn = self.svgis_obj._feature(feat, [], classes=['foo'], id_field='cat')
drawn = self.svgis_obj._feature(feat, [], classes=['foo'], id_field='cat', name='quux')
assert isinstance(drawn, six.string_types)

self.assertIn('id="meow"', drawn)
self.assertIn('class="foo_bar"', drawn)
self.assertIn('class="quux foo_bar"', drawn)

drawn2 = self.svgis_obj._feature(feat, [], classes=['foo'], id_field='cat')
self.assertIn('class="foo_bar"', drawn2)

def testSvgisComposeType(self):
a = self.svgis_obj.compose(inline_css=True)
Expand Down Expand Up @@ -143,8 +146,8 @@ def testMapFunc(self):
assert 'stroke-linejoin:round' in style

def testDrawWithClasses(self):
r0 = self.svgis_obj._feature(self.polygon, [], classes=['potato'], id_field=None)
assert 'class="potato"' in r0
r0 = self.svgis_obj._feature(self.polygon, [], classes=[], id_field=None, name='potato')
self.assertIn('class="potato"', r0)

r1 = self.svgis_obj._feature(self.polygon, [], classes=['kale'], id_field='apple')
assert 'kale_leafy_green' in r1
Expand Down

0 comments on commit 2ff8c83

Please sign in to comment.