From 9bca570fa76d50b5161508f009d9c37bbefad358 Mon Sep 17 00:00:00 2001 From: Famlam Date: Fri, 17 Nov 2023 21:10:19 +0100 Subject: [PATCH] Improve class 31608 description - Ensure the full tag is stored in `stars` so that the tag is available for the message. - A nice side effect is that both class 31608 and 31603 now also detect conflicts between for example (31603: `destination:ref:lanes` and `destination:ref:lanes:forward`) or (31608: `lanes(destination:ref:lanes:backward)=2` + `lanes(destination:lanes:backward)=1)`. Previously those were undetected - Avoid outputting confusing messages like `lanes(lanes:lanes)=1` when there is no tag `lanes:lanes`, or `lanes(lanes:*:backward)=2` when the tag is actually `lanes:backward`. - Add some comments to the code --- plugins/Highway_Lanes.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/plugins/Highway_Lanes.py b/plugins/Highway_Lanes.py index 3a70b8d54..3f6f977c2 100644 --- a/plugins/Highway_Lanes.py +++ b/plugins/Highway_Lanes.py @@ -219,6 +219,7 @@ def way(self, data, tags, nds): if o: non_fullwidth_lanes_number[direction] = ilen(filter(lambda i: i == 'designated', o.split('|'))) + # Verify *:lanes tags are not numerical for access in ['hgv', 'bus', 'access', 'bicycle', 'psv', 'taxi', 'vehicle', 'motor_vehicle', 'hov', 'motorcycle', 'goods']: base = access+':lanes' for tag in tags_lanes: @@ -230,14 +231,10 @@ def way(self, data, tags, nds): # Ok, should not be an integer pass - stars = [] - for tag in tags_lanes: - if ":lanes" in tag: - star = tag.split(':')[0] - if star not in ('source', 'proposed', 'construction', 'note'): - stars.append(star) - stars = list(set(stars)) + # Get all * in *:lanes suffixed keys + stars = set(map(lambda tag: tag.split(":lanes")[0], filter(lambda tag: ":lanes" in tag and tag.split(":")[0] not in ('source', 'proposed', 'construction', 'note'), tags_lanes))) + # Verify *:lanes doesn't co-exist with *:lanes:[direction] for star in stars: if star + ':lanes' in tags_lanes: for direction in [':forward', ':backward', ':both_ways']: @@ -247,6 +244,8 @@ def way(self, data, tags, nds): if err != []: return err + # 1. Collects the values of lanes and lanes:[direction] only + # 2. Validates all lanes:* to be numerical number = {'lanes': {}} for tag in tags_lanes: if tag == 'lanes' or tag.startswith('lanes:'): @@ -260,6 +259,7 @@ def way(self, data, tags, nds): except ValueError: err.append({"class": 31601, "subclass": 0 + stablehash64(tag), "text": T_("lanes={0} is not an integer", tags_lanes[tag])}) + # Count the number of lanes in *:lanes tags for star in stars: number[star] = {} for direction in ['', ':forward', ':backward', ':both_ways']: @@ -267,23 +267,28 @@ def way(self, data, tags, nds): if o: number[star][direction] = len(o.split('|')) + # Check if the number of lanes matches within tags of the same direction n_lanes = {} for direction in ['', ':forward', ':backward', ':both_ways']: tag = None for star in sorted(number.keys()): non_fullwidth_lanes_number_star = ((non_fullwidth_lanes_number.get(direction) or 0) if star != 'lanes' else 0) - non_fullwidth_lanes_number_tag = ((non_fullwidth_lanes_number.get(direction) or 0) if tag != 'lanes:lanes'+direction else 0) + non_fullwidth_lanes_number_tag = ((non_fullwidth_lanes_number.get(direction) or 0) if tag != 'lanes' + direction else 0) if n_lanes.get(direction) is not None and number[star].get(direction) is not None and \ (number[star][direction] - non_fullwidth_lanes_number_star > n_lanes[direction] or n_lanes[direction] - non_fullwidth_lanes_number_tag > number[star][direction]): err.append({"class": 31608, "subclass": 0 + stablehash64(direction + '|' + star), "text": { "en": "(lanes({0})={1}) - (non fullwidth={2}) != (lanes({3})={4}) - (non fullwidth={5})".format( - star+":*"+direction, number[star][direction], non_fullwidth_lanes_number_star, - tag, n_lanes[direction], non_fullwidth_lanes_number_tag) }}) + star + ":lanes" + direction if star != "lanes" else star + direction, + number[star][direction], + non_fullwidth_lanes_number_star, + tag, + n_lanes[direction], + non_fullwidth_lanes_number_tag) }}) elif n_lanes.get(direction) is None and number[star].get(direction) is not None: # First loop, pick the star as tag and the number of lanes to compare to the others n_lanes[direction] = number[star][direction] - tag = star+":lanes"+direction + tag = star + ":lanes" + direction if star != "lanes" else star + direction if err != []: return err @@ -364,6 +369,7 @@ def test(self): {"highway": "residential", "lanes": "2", "lanes:backward": "2"}, {"highway": "residential", "lanes": "3", "lanes:backward": "2", "lanes:forward": "2"}, {"highway": "another", "oneway": "yes", "vehicle:lanes": "yes|yes|yes|no|no|no|no", "bicycle:lanes": "designated|designated", "turn:lanes": "||||"}, + {"highway": "another", "oneway": "yes", "destination:lanes": "A|B", "destination:color:lanes": "A|B|C"}, ]: self.check_err(a.way(None, t, None), t) @@ -389,6 +395,7 @@ def test(self): {"highway": "secondary", "lanes": "1", "width:lanes": "3|1.5|1.5", "access:lanes": "yes|no|no", "bicycle:lanes": "yes|designated|designated"}, {"highway": "tertiary", "lanes": "6", "lanes:forward": "4", "lanes:backward": "2", "bus:lanes:backward": "yes|designated", "bicycle:lanes:backward": "yes|designated", "cycleway": "opposite_share_busway"}, {"highway": "tertiary", "lanes": "3", "bus:lanes": "||designated", "bicycle:lanes": "no|designated|designated", "turn:lanes": "through|through|right"}, + {"highway": "residential", "destination:lanes:both_ways": "x|y", "destination:lanes:backward": "y"}, ]: assert not a.way(None, t, None), a.way(None, t, None)