Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 9 additions & 23 deletions src/mapcss/StyleChooser.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,13 @@ def extract_tags(self):
return a

def get_runtime_conditions(self, tags):
"""
Returns the runtime conditions of every ::object-id this chooser selects,
to match the testChainsAll() contract used by updateStyles().
"""
if not self.has_runtime_conditions:
return None

rule_and_object_id = self.testChains(tags)

if not rule_and_object_id:
return None

rule = rule_and_object_id[0]

return rule.runtime_conditions
return []
return [rule.runtime_conditions for rule, _ in self.testChainsAll(tags) if rule.runtime_conditions]

# TODO: Rename to "applyStyles"
def updateStyles(self, sl, tags, xscale, zscale, filter_by_runtime_conditions):
Expand Down Expand Up @@ -180,9 +176,9 @@ def applyStylesTo(self, sl, tags, xscale, zscale, filter_by_runtime_conditions,

def testChainsAll(self, tags):
"""
Like testChains(), but yields the first matching rule for *each* distinct
::object-id of the selector group, so that a declaration block applies to
every layer it selects instead of just the first one.
Yields the first matching rule for *each* distinct ::object-id of the
selector group, so that a declaration block applies to every layer it
selects instead of just the first one.
"""
object_ids = set()
for r in self.ruleChains:
Expand All @@ -191,16 +187,6 @@ def testChainsAll(self, tags):
object_ids.add(tt)
yield r, tt

def testChains(self, tags):
"""
Tests an object against a chain
"""
for r in self.ruleChains:
tt = r.test(tags)
if tt:
return r, tt
return False

def newGroup(self):
"""
starts a new ruleChain in this.ruleChains
Expand Down
4 changes: 1 addition & 3 deletions src/mapcss/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,7 @@ def get_runtime_rules(self, clname, type, tags, zoom):
runtime_rules = []
if type in self.choosers_by_type_zoom_tag:
for chooser in self.choosers_by_type_zoom_tag[type][zoom][clname]:
runtime_conditions = chooser.get_runtime_conditions(tags)
if runtime_conditions:
runtime_rules.append(runtime_conditions)
runtime_rules.extend(chooser.get_runtime_conditions(tags))
return runtime_rules

# TODO: Renamed to `get_styles` because it returns a list of styles for each class `::XXX`
Expand Down
12 changes: 4 additions & 8 deletions tests/testMapCSS.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ def test_parse_basic_chooser_2(self):
self.assertEqual(parser.choosers[0].selzooms, [6, 6])
self.assertEqual(parser.choosers[1].selzooms, [7, 9])

rule, object_id = parser.choosers[0].testChains({"highway": "trunk"})
self.assertEqual(object_id, "::default")
self.assertEqual(parser.choosers[0].ruleChains[0].test({"highway": "trunk"}), "::default")

def test_parse_basic_chooser_3(self):
parser = MapCSS()
Expand All @@ -137,10 +136,9 @@ def test_parse_basic_chooser_3(self):
styleChooser = parser.choosers[0]
self.assertEqual(len(styleChooser.ruleChains), 1)
self.assertEqual(styleChooser.selzooms, [18, 19])
rule, object_id = styleChooser.testChains(building_tags)
self.assertEqual(object_id, "::int_name")

rule = styleChooser.ruleChains[0]
self.assertEqual(rule.test(building_tags), "::int_name")
self.assertEqual(rule.subject, 'node')
self.assertEqual(rule.extract_tags(), {'addr:housenumber', 'addr:street'})

Expand All @@ -158,10 +156,9 @@ def test_parse_basic_chooser_class(self):
styleChooser = parser.choosers[0]
self.assertEqual(len(styleChooser.ruleChains), 1)
self.assertEqual(styleChooser.selzooms, [0, 13])
rule, object_id = styleChooser.testChains({})
self.assertEqual(object_id, "::*")

rule = styleChooser.ruleChains[0]
self.assertEqual(rule.test({}), "::*")
self.assertEqual(rule.subject, 'way')
self.assertEqual(rule.extract_tags(), {'*'})

Expand All @@ -179,10 +176,9 @@ def test_parse_basic_chooser_class_2(self):
styleChooser = parser.choosers[0]
self.assertEqual(len(styleChooser.ruleChains), 1)
self.assertEqual(styleChooser.selzooms, [10, 19])
rule, object_id = styleChooser.testChains({})
self.assertEqual(object_id, "::*")

rule = styleChooser.ruleChains[0]
self.assertEqual(rule.test({}), "::*")
self.assertEqual(rule.subject, 'way')
self.assertEqual(rule.extract_tags(), {'*'})

Expand Down
41 changes: 31 additions & 10 deletions tests/testStyleChooser.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,13 @@ def test_rules_chain(self):
sc.addCondition(parseCondition("footway=crossing"))
sc.addCondition(Condition("eq", ("::class", "::*")))

self.assertTrue( sc.testChains({ "highway": "footway", "footway": "sidewalk" }) )
self.assertTrue( sc.testChains({ "highway": "footway", "footway": "crossing" }) )
self.assertFalse( sc.testChains({ "highway": "footway"}) )
self.assertFalse( sc.testChains({ "highway": "residential", "footway": "crossing" }) )
self.assertEqual( list(sc.testChainsAll({ "highway": "footway" })), [] )
self.assertEqual( list(sc.testChainsAll({ "highway": "residential", "footway": "crossing" })), [] )

rule1, tt = sc.testChains({ "highway": "footway", "footway": "sidewalk" })
rule1, tt = next(sc.testChainsAll({ "highway": "footway", "footway": "sidewalk" }))
self.assertEqual(tt, "::default")

rule2, tt = sc.testChains({ "highway": "footway", "footway": "crossing" })
rule2, tt = next(sc.testChainsAll({ "highway": "footway", "footway": "crossing" }))
self.assertEqual(tt, "::*")

self.assertNotEqual(rule1, rule2)
Expand All @@ -51,11 +49,11 @@ def test_zoom(self):
sc.addCondition(parseCondition("transport=subway"))
sc.addCondition(parseCondition("city=yokohama"))

rule1, tt = sc.testChains({ "railway": "station", "transport": "subway", "city": "yerevan" })
rule1, tt = next(sc.testChainsAll({ "railway": "station", "transport": "subway", "city": "yerevan" }))
self.assertEqual(rule1.minZoom, 10)
self.assertEqual(rule1.maxZoom, 19)

rule2, tt = sc.testChains({ "railway": "station", "transport": "subway", "city": "yokohama" })
rule2, tt = next(sc.testChainsAll({ "railway": "station", "transport": "subway", "city": "yokohama" }))
self.assertEqual(rule2.minZoom, 4)
self.assertEqual(rule2.maxZoom, 15)

Expand Down Expand Up @@ -289,8 +287,31 @@ def test_update_styles_by_class_all(self):


def test_runtime_conditions(self):
# TODO: Create test with sc.addRuntimeCondition(Condition(condType, ('extra_tag', cond)))
pass
# libkomwm builds one drule variant per reported condition set, so every
# selected `::object-id` must report its own: the styles of an object-id
# left out are dropped by the filter_by_runtime_conditions check.
sc = StyleChooser((4, 19))

sc.newObject()
sc.addCondition(Condition("eq", ("::class", "::default")))
sc.addCondition(parseCondition("place=city"))
sc.addRuntimeCondition(parseCondition("population>=1000"))

sc.newObject()
sc.addCondition(Condition("eq", ("::class", "::int_name")))
sc.addCondition(parseCondition("place=city"))
sc.addRuntimeCondition(parseCondition("population>=500"))

object_tags = {"place": "city"}

self.assertEqual([[str(c) for c in rc] for rc in sc.get_runtime_conditions(object_tags)],
[["population>=1000"], ["population>=500"]])

# A chooser without runtime conditions reports none.
sc_plain = StyleChooser((4, 19))
sc_plain.newObject()
sc_plain.addCondition(parseCondition("place=city"))
self.assertEqual(sc_plain.get_runtime_conditions(object_tags), [])

if __name__ == '__main__':
unittest.main()
Loading