Skip to content

Commit 945e95c

Browse files
authored
Implement tree-vs-wiki check (#2224)
1 parent 25f7df7 commit 945e95c

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

plugins/TagFix_Tree.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#-*- coding: utf-8 -*-
2+
3+
###########################################################################
4+
## ##
5+
## Copyrights Osmose project 2024 ##
6+
## ##
7+
## This program is free software: you can redistribute it and/or modify ##
8+
## it under the terms of the GNU General Public License as published by ##
9+
## the Free Software Foundation, either version 3 of the License, or ##
10+
## (at your option) any later version. ##
11+
## ##
12+
## This program is distributed in the hope that it will be useful, ##
13+
## but WITHOUT ANY WARRANTY; without even the implied warranty of ##
14+
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ##
15+
## GNU General Public License for more details. ##
16+
## ##
17+
## You should have received a copy of the GNU General Public License ##
18+
## along with this program. If not, see <http://www.gnu.org/licenses/>. ##
19+
## ##
20+
###########################################################################
21+
22+
from modules.OsmoseTranslation import T_
23+
from plugins.Plugin import Plugin
24+
from modules.downloader import urlread
25+
26+
27+
class TagFix_Tree(Plugin):
28+
29+
def _read_leaf_properties_table(self):
30+
# The documented values, excluding:
31+
# - mixed leaf types/cycles: not compatible with `species`
32+
# - leaf_cycle = semi_*: might be climate dependent and unclear difference between semi_evergreen and semi_deciduous, see #2224 first comment
33+
allowed_leaf_type = ("broadleaved", "needleleaved", "leafless")
34+
allowed_leaf_cycle = ("evergreen", "deciduous")
35+
36+
data = urlread(u"https://wiki.openstreetmap.org/w/index.php?title=Tag:natural%3Dtree/List_of_Species&action=raw", 1)
37+
data = list(map(lambda x: list(filter(lambda z: len(z) > 0, map(lambda y: y.strip(), x.split("|")))), data.split("|-")[1:-1]))
38+
species_map = {}
39+
for row in data: # data: list of [species, species:wikidata, leaf_cycle, leaf_type]
40+
this_species = {}
41+
if row[2] in allowed_leaf_cycle:
42+
this_species['leaf_cycle'] = row[2]
43+
if row[3] in allowed_leaf_type:
44+
this_species['leaf_type'] = row[3]
45+
if len(this_species) > 0:
46+
if len(row[1]) > 2 and row[1][0] == "Q":
47+
this_species['species:wikidata'] = row[1]
48+
species_map[row[0]] = this_species
49+
return species_map
50+
51+
def init(self, logger):
52+
Plugin.init(self, logger)
53+
54+
self.errors[31201] = self.def_class(item = 3120, level = 3, tags = ['tree', 'natural', 'fix:chair'],
55+
title = T_('Conflicting tree properties'),
56+
detail = T_(
57+
'''The leaf type and/or leaf cycle does not match with the species.'''),
58+
fix = T_(
59+
'''Verify that the species is correct, before adding the leaf properties.'''),
60+
resource = 'https://wiki.openstreetmap.org/wiki/Tag:natural%3Dtree/List_of_Species')
61+
62+
# Read the wiki
63+
self.species_map = self._read_leaf_properties_table()
64+
65+
def _check_leaf_properties(self, tags):
66+
err = []
67+
68+
if "species" in tags and tags["species"] in self.species_map:
69+
expected_tags = self.species_map[tags["species"]]
70+
71+
if "leaf_cycle" in tags and tags["leaf_cycle"].startswith("semi_"):
72+
# Ignore leaf_cycle if it already has a value `semi_*`. This might be climate dependent,
73+
# and unclear difference between semi_evergreen and semi_deciduous, see #2224 first comment
74+
expected_tags = {x: expected_tags[x] for x in filter(lambda x: x != "leaf_cycle", expected_tags)}
75+
76+
# The tags do not match with the data on the wiki. Don't check for wikidata (handled in item 3031)
77+
mismatches = set(filter(lambda t: t in tags and expected_tags[t] != tags[t] and t != "species:wikidata", expected_tags.keys()))
78+
if len(mismatches) > 0:
79+
err.append({
80+
"class": 31201,
81+
"text": T_("Conflict between `{0}` and `{1}`", "`, `".join(mismatches), "species"),
82+
"fix": [
83+
{"~": {x: expected_tags[x] for x in mismatches}, "+": {x: expected_tags[x] for x in list(filter(lambda t: t not in tags, expected_tags.keys()))}},
84+
{"-": ["species"]}
85+
]})
86+
87+
return err
88+
89+
def node(self, data, tags):
90+
if "natural" in tags and tags["natural"] == "tree":
91+
return self._check_leaf_properties(tags)
92+
93+
def way(self, data, tags, nds):
94+
if "natural" in tags and tags["natural"] == "tree_row":
95+
return self._check_leaf_properties(tags)
96+
97+
98+
99+
###########################################################################
100+
from plugins.Plugin import TestPluginCommon
101+
102+
class Test(TestPluginCommon):
103+
def test(self):
104+
a = TagFix_Tree(None)
105+
a.init(None)
106+
107+
for t in [{"natural": "tree"},
108+
{"natural": "tree", "leaf_type": "broadleaved"},
109+
{"natural": "tree", "leaf_cycle": "deciduous"},
110+
{"natural": "tree", "leaf_cycle": "deciduous", "leaf_type": "broadleaved"},
111+
{"natural": "tree", "leaf_cycle": "deciduous", "leaf_type": "broadleaved", "species": "Acer buergerianum"},
112+
{"natural": "tree", "leaf_cycle": "semi_deciduous", "leaf_type": "broadleaved", "species": "Acer buergerianum"}, # Ignore semi_*, see #2224 first comment
113+
{"natural": "tree", "leaf_cycle": "deciduous", "leaf_type": "broadleaved", "species": "Acer buergerianum", "species:wikidata": "Q941891"},
114+
{"natural": "tree", "leaf_cycle": "deciduous", "leaf_type": "broadleaved", "species": "Acer buergerianum", "species:wikidata": "Q123456789"}, # Bad wikidata is handled by item 3031
115+
{"natural": "tree", "leaf_cycle": "deciduous", "leaf_type": "broadleaved", "species": "Unknown species"},
116+
{"natural": "tree", "species": "Unknown species"},
117+
]:
118+
assert not a.node(None, t), a.node(None, t)
119+
120+
# Mismatching properties
121+
for t in [{"natural": "tree", "leaf_cycle": "deciduous", "leaf_type": "needleleaved", "species": "Acer buergerianum"},
122+
{"natural": "tree", "leaf_cycle": "evergreen", "leaf_type": "broadleaved", "species": "Acer buergerianum"},
123+
{"natural": "tree", "leaf_cycle": "evergreen", "leaf_type": "broadleaved", "species": "Acer buergerianum", "species:wikidata": "Q941891"},
124+
{"natural": "tree", "leaf_cycle": "evergreen", "leaf_type": "needleleaved", "species": "Acer buergerianum"},
125+
{"natural": "tree", "leaf_cycle": "evergreen", "species": "Acer buergerianum"},
126+
]:
127+
assert a.node(None, t), a.node(None, t)

0 commit comments

Comments
 (0)