2222###########################################################################
2323
2424from modules .OsmoseTranslation import T_
25- from .Analyser_Merge import (
26- Analyser_Merge_Point ,
27- Source ,
28- CSV ,
29- Load_XY ,
30- Conflate ,
31- Select ,
32- Mapping ,
33- )
25+ from .Analyser_Merge import Analyser_Merge_Point , Source , CSV , Load_XY , Conflate , Select , Mapping
3426
3527
3628class Analyser_Merge_Charging_station_FR (Analyser_Merge_Point ):
37- # Constante pour limiter les valeurs aberrantes (en kW)
29+ # constant to limit bad formatting in open data (in kW)
3830 MAX_POWER_KW = 401
3931 WIKIDATA_MAP = {
4032 "ionity" : "Q42717773" ,
@@ -50,29 +42,27 @@ class Analyser_Merge_Charging_station_FR(Analyser_Merge_Point):
5042 @staticmethod
5143 def keepMaxValueIfEnum (str_val ):
5244
53- # si la valeur contient un ; on sépare et on prend la plus haute valeur
45+ # if the value contains a semicolon, we split it and keep only the highest value
5446 if ";" in str_val :
5547 boom = str_val .split (";" )
5648 max_val = 0
5749 for p in boom :
58- # Supprimer les unités éventuelles (comme "kw")
5950 p_clean = p .lower ().replace ("kw" , "" ).strip ()
6051 try :
6152 p_val = int (float (p_clean ))
62- # Ignorer les valeurs supérieures à la limite maximale connue (MAX_POWER_KW)
6353 if (
6454 p_val <= Analyser_Merge_Charging_station_FR .MAX_POWER_KW
6555 and p_val > max_val
6656 ):
6757 max_val = p_val
6858 except ValueError :
69- # Ignorer les valeurs qui ne peuvent pas être converties en nombre
59+ # exclude values we can not convert to number
7060 pass
7161
7262 if max_val > 0 :
7363 str_val = str (max_val )
7464 else :
75- # Gérer les cas où il n'y a pas de délimiteur mais une unité est présente
65+ # case without delimiter, handle unit
7666 if "kw" in str_val .lower ():
7767 p_clean = str_val .lower ().replace ("kw" , "" ).strip ()
7868 try :
@@ -84,7 +74,7 @@ def keepMaxValueIfEnum(str_val):
8474 return str_val
8575
8676 def _normalize_number (self , v : float ) -> str :
87- """Formate un float en supprimant les .0 inutiles et les zéros de fin ."""
77+ """Formats in float by removing unwanted zeros ."""
8878 try :
8979 iv = int (v )
9080 if abs (v - iv ) < 1e-9 :
@@ -94,20 +84,7 @@ def _normalize_number(self, v: float) -> str:
9484 return str (v )
9585
9686 def getPuissanceNominaleInKw (self , raw ):
97- """
98- Calcule la puissance nominale en kW à partir d'une valeur brute.
99-
100- Règles:
101- - Si 'raw' est une énumération 'a;b;c', on garde la valeur max en kW <= MAX_POWER_KW.
102- - Si 'raw' est une valeur unique:
103- * suffixe 'kW' => valeur déjà en kW
104- * suffixe 'W' => conversion W -> kW
105- * sans unité:
106- - si > MAX_POWER_KW => on suppose des watts, on divise par 1000
107- - sinon => déjà en kW
108-
109- Retour: 'X kW' ou None si indéterminable.
110- """
87+ """Computes nominal power in kW from a possible enumeration of values."""
11188 if raw is None :
11289 return None
11390
@@ -117,7 +94,7 @@ def getPuissanceNominaleInKw(self, raw):
11794
11895 max_kw = getattr (self , "MAX_POWER_KW" , 500 )
11996
120- # Cas énumération: on délègue à keepMaxValueIfEnum puis on formate .
97+ # enumeration case: we only want the max value and format it .
12198 if ";" in s :
12299 max_str = self .keepMaxValueIfEnum (s )
123100 if not max_str :
@@ -130,7 +107,7 @@ def getPuissanceNominaleInKw(self, raw):
130107 return None
131108 return f"{ self ._normalize_number (v )} kW"
132109
133- # Cas valeur unique
110+ # case of only one value
134111 s_norm = s .lower ().replace ("," , "." )
135112 try :
136113 if s_norm .endswith ("kw" ):
@@ -142,7 +119,7 @@ def getPuissanceNominaleInKw(self, raw):
142119 v = v_w / 1000.0
143120 return f"{ self ._normalize_number (v )} kW"
144121
145- # Sans unité
122+ # case without unit
146123 v = float (s_norm )
147124 if v > max_kw :
148125 # On suppose des watts => conversion en kW
@@ -154,73 +131,48 @@ def getPuissanceNominaleInKw(self, raw):
154131 def __init__ (self , config , logger = None ):
155132 Analyser_Merge_Point .__init__ (self , config , logger )
156133 doc = dict (
157- detail = T_ (
158- """A car charging station may be here but is not mapped. The list of the
159- charging stations comes from a database published by Etalab. This database
160- brings together information published by the various local authorities and
161- networks in France."""
162- ),
163- fix = T_ (
164- """See [the
165- mapping](https://wiki.openstreetmap.org/wiki/France/data.gouv.fr/Bornes_de_Recharge_pour_V%C3%A9hicules_%C3%89lectriques)
166- on the wiki. Add a node or add tags if already existing."""
167- ),
168- trap = T_ (
169- """The initial information corresponds to recharging pools and devices and not to
170- stations, so some values are worth checking in the field. For instance, an open data point
171- with `capacity=6` can sometimes match to 3 charging station with `capacity=2`"""
172- ),
173- )
174- self .def_class_missing_official (
175- item = 8410 ,
176- id = 1 ,
177- level = 3 ,
178- tags = ["merge" , "fix:imagery" , "fix:survey" , "fix:picture" ],
179- title = T_ ("Car charging station not integrated" ),
180- ** doc ,
181- )
182- self .def_class_possible_merge (
183- item = 8411 ,
184- id = 3 ,
185- level = 3 ,
186- tags = ["merge" , "fix:imagery" , "fix:survey" , "fix:picture" ],
187- title = T_ ("Car charging station, integration suggestion" ),
188- ** doc ,
189- )
190- self .def_class_update_official (
191- item = 8412 ,
192- id = 4 ,
193- level = 3 ,
194- tags = ["merge" , "fix:imagery" , "fix:survey" , "fix:picture" ],
195- title = T_ ("Car charging station update" ),
196- ** doc ,
197- )
134+ detail = T_ (
135+ '''A car charging station may be here but is not mapped. The list of the
136+ charging stations comes from a database published by Etalab. This database
137+ brings together information published by the various local authorities and
138+ networks in France.''' ),
139+ fix = T_ (
140+ '''See [the
141+ mapping](https://wiki.openstreetmap.org/wiki/France/data.gouv.fr/Bornes_de_Recharge_pour_V%C3%A9hicules_%C3%89lectriques)
142+ on the wiki. Add a node or add tags if already existing.''' ),
143+ trap = T_ (
144+ '''The initial information corresponds to recharging pools and devices and not to
145+ stations, so some values are worth checking in the field. For instance, an open data point
146+ with `capacity=6` can sometimes match to 3 charging station with `capacity=2`''' ))
147+ self .def_class_missing_official (item = 8410 , id = 1 , level = 3 , tags = ['merge' , 'fix:imagery' , 'fix:survey' , 'fix:picture' ],
148+ title = T_ ('Car charging station not integrated' ), ** doc )
149+ self .def_class_possible_merge (item = 8411 , id = 3 , level = 3 , tags = ['merge' , 'fix:imagery' , 'fix:survey' , 'fix:picture' ],
150+ title = T_ ('Car charging station, integration suggestion' ), ** doc )
151+ self .def_class_update_official (item = 8412 , id = 4 , level = 3 , tags = ['merge' , 'fix:imagery' , 'fix:survey' , 'fix:picture' ],
152+ title = T_ ('Car charging station update' ), ** doc )
198153
199154 self .init (
200155 "https://transport.data.gouv.fr/datasets/fichier-consolide-des-bornes-de-recharge-pour-vehicules-electriques/" ,
201156 "Stations de recharge pour véhicules électriques" ,
202- CSV (
203- Source (
204- attribution = "data.gouv.fr:Etalab" ,
205- millesime = "05/2022" ,
206- fileUrl = "https://raw.githubusercontent.com/Jungle-Bus/ref-EU-EVSE/gh-pages/opendata_stations.csv" ,
207- )
208- ),
157+ CSV (Source (attribution = "data.gouv.fr:Etalab" , millesime = "05/2022" ,
158+ fileUrl = "https://raw.githubusercontent.com/Jungle-Bus/ref-EU-EVSE/gh-pages/opendata_stations.csv" )),
209159 Load_XY ("Xlongitude" , "Ylatitude" ),
210160 Conflate (
211161 select = Select (
212- types = ["nodes" , "ways" ], tags = { "amenity" : "charging_station" }
213- ),
162+ types = ["nodes" , "ways" ],
163+ tags = { "amenity" : "charging_station" } ),
214164 conflationDistance = 100 ,
215165 osmRef = "ref:EU:EVSE" ,
216166 mapping = Mapping (
217- static1 = {"amenity" : "charging_station" , "motorcar" : "yes" },
167+ static1 = {
168+ "amenity" : "charging_station" ,
169+ "motorcar" : "yes" },
218170 static2 = {"source" : self .source },
219171 mapping1 = {
220172 "operator" : "nom_operateur" ,
221173 "network" : "nom_enseigne" ,
222174 "owner" : "nom_amenageur" ,
223- "ref:EU:EVSE" : "id_station_itinerance" ,
175+ "ref:EU:EVSE" : "id_station_itinerance"
224176 },
225177 mapping2 = {
226178 "charging_station:output" : lambda fields : self .getPuissanceNominaleInKw (
@@ -230,87 +182,20 @@ def __init__(self, config, logger=None):
230182 "operator:email" : "contact_operateur" ,
231183 "start_date" : "date_mise_en_service" ,
232184 "capacity" : "nbre_pdc" ,
233- "bicycle" : lambda fields : (
234- "yes" if fields ["station_deux_roues" ] == "true" else None
235- ),
236- "motorcycle" : lambda fields : (
237- "yes" if fields ["station_deux_roues" ] == "true" else None
238- ),
239- "moped" : lambda fields : (
240- "yes" if fields ["station_deux_roues" ] == "true" else None
241- ),
242- "motorcar" : lambda fields : (
243- "no" if fields ["station_deux_roues" ] == "true" else "yes"
244- ),
185+ "bicycle" : lambda fields : "yes" if fields ["station_deux_roues" ] == "true" else None ,
186+ "motorcycle" : lambda fields : "yes" if fields ["station_deux_roues" ] == "true" else None ,
187+ "moped" : lambda fields : "yes" if fields ["station_deux_roues" ] == "true" else None ,
188+ "motorcar" : lambda fields : "no" if fields ["station_deux_roues" ] == "true" else "yes" ,
245189 "opening_hours" : "horaires_grouped" ,
246- "fee" : lambda fields : (
247- "yes"
248- if fields ["gratuit_grouped" ] == "false"
249- else ("no" if fields ["gratuit_grouped" ] == "true" else None )
250- ),
251- "authentication:none" : lambda fields : (
252- "yes" if fields ["paiement_acte_grouped" ] == "true" else None
253- ),
254- "payment:credit_cards" : lambda fields : (
255- "yes"
256- if fields ["paiement_cb_grouped" ] == "true"
257- else (
258- "no"
259- if fields ["paiement_cb_grouped" ] == "false"
260- else None
261- )
262- ),
263- "reservation" : lambda fields : (
264- "yes" if fields ["reservation_grouped" ] == "true" else None
265- ),
266- "wheelchair" : lambda fields : (
267- "yes"
268- if fields ["accessibilite_pmr_grouped" ]
269- == "Accessible mais non réservé PMR"
270- else (
271- "no"
272- if fields ["accessibilite_pmr_grouped" ]
273- == "Non accessible"
274- else None
275- )
276- ),
277- "socket:typee" : lambda fields : (
278- fields ["nb_EF_grouped" ]
279- if fields ["nb_EF_grouped" ] != "0"
280- else None
281- ),
282- "socket:type2" : lambda fields : (
283- fields ["nb_T2_grouped" ]
284- if fields ["nb_T2_grouped" ] != "0"
285- else None
286- ),
287- "socket:type2_combo" : lambda fields : (
288- fields ["nb_combo_ccs_grouped" ]
289- if fields ["nb_combo_ccs_grouped" ] != "0"
290- else None
291- ),
292- "socket:chademo" : lambda fields : (
293- fields ["nb_chademo_grouped" ]
294- if fields ["nb_chademo_grouped" ] != "0"
295- else None
296- ),
297- "wikimedia:network" : lambda fields : (
298- self .WIKIDATA_MAP .get (fields ["nom_enseigne" ].lower (), None )
299- if fields ["nom_enseigne" ] != "0"
300- else None
301- ),
302- },
303- text = lambda tags , fields : {
304- "en" : "{0}, {1}, {2}" .format (
305- fields ["nom_station" ],
306- fields ["adresse_station" ],
307- (
308- fields ["observations" ]
309- if fields ["observations" ] != "null"
310- else "-"
311- ),
312- )
190+ "fee" : lambda fields : "yes" if fields ["gratuit_grouped" ] == "false" else ("no" if fields ["gratuit_grouped" ] == "true" else None ),
191+ "authentication:none" : lambda fields : "yes" if fields ["paiement_acte_grouped" ] == "true" else None ,
192+ "payment:credit_cards" : lambda fields : "yes" if fields ["paiement_cb_grouped" ] == "true" else ("no" if fields ["paiement_cb_grouped" ] == "false" else None ),
193+ "reservation" : lambda fields : "yes" if fields ["reservation_grouped" ] == "true" else None ,
194+ "wheelchair" : lambda fields : "yes" if fields ["accessibilite_pmr_grouped" ] == "Accessible mais non réservé PMR" else ("no" if fields ["accessibilite_pmr_grouped" ] == "Non accessible" else None ),
195+ "socket:typee" : lambda fields : fields ["nb_EF_grouped" ] if fields ["nb_EF_grouped" ] != "0" else None ,
196+ "socket:type2" : lambda fields : fields ["nb_T2_grouped" ] if fields ["nb_T2_grouped" ] != "0" else None ,
197+ "socket:type2_combo" : lambda fields : fields ["nb_combo_ccs_grouped" ] if fields ["nb_combo_ccs_grouped" ] != "0" else None ,
198+ "socket:chademo" : lambda fields : fields ["nb_chademo_grouped" ] if fields ["nb_chademo_grouped" ] != "0" else None ,
199+ "wikimedia:network" : lambda fields : self .WIKIDATA_MAP .get (fields ["nom_enseigne" ].lower (), None ) if fields ["nom_enseigne" ] != "0" else None ,
313200 },
314- ),
315- ),
316- )
201+ text = lambda tags , fields : {"en" : "{0}, {1}, {2}" .format (fields ["nom_station" ], fields ["adresse_station" ], fields ["observations" ] if fields ["observations" ] != "null" else "-" )})))
0 commit comments