Skip to content

Commit 1953c42

Browse files
committed
src - Add and fix some type hints
1 parent ee4f851 commit 1953c42

File tree

3 files changed

+70
-47
lines changed

3 files changed

+70
-47
lines changed

overpy/__init__.py

Lines changed: 47 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
__uri__, __version__
1818
)
1919

20-
ElementTypeVar = TypeVar("ElementTypeVar", Type["Area"], Type["Node"], Type["Relation"], Type["Way"])
20+
ElementTypeVar = TypeVar("ElementTypeVar", bound="Element")
2121

2222
XML_PARSER_DOM = 1
2323
XML_PARSER_SAX = 2
@@ -33,7 +33,9 @@
3333
}
3434

3535

36-
def is_valid_type(element: "Element", cls: Type["Element"]) -> bool:
36+
def is_valid_type(
37+
element: Union["Area", "Node", "Relation", "Way"],
38+
cls: Type[Union["Area", "Element", "Node", "Relation", "Way"]]) -> bool:
3739
"""
3840
Test if an element is of a given type.
3941
@@ -119,9 +121,9 @@ def query(self, query: Union[bytes, str]) -> "Result":
119121
if not isinstance(query, bytes):
120122
query = query.encode("utf-8")
121123

122-
retry_num = 0
124+
retry_num: int = 0
123125
retry_exceptions: List[exception.OverPyException] = []
124-
do_retry = True if self.max_retry_count > 0 else False
126+
do_retry: bool = True if self.max_retry_count > 0 else False
125127
while retry_num <= self.max_retry_count:
126128
if retry_num > 0:
127129
time.sleep(self.retry_timeout)
@@ -156,7 +158,7 @@ def query(self, query: Union[bytes, str]) -> "Result":
156158
continue
157159

158160
if f.code == 400:
159-
msgs = []
161+
msgs: List[str] = []
160162
for msg_raw in self._regex_extract_error_msg.finditer(response):
161163
msg_clean_bytes = self._regex_remove_tag.sub(b"", msg_raw.group("msg"))
162164
try:
@@ -239,7 +241,7 @@ class Result:
239241

240242
def __init__(
241243
self,
242-
elements: Optional[List["Element"]] = None,
244+
elements: Optional[List[Union["Area", "Node", "Relation", "Way"]]] = None,
243245
api: Optional[Overpass] = None):
244246
"""
245247
@@ -248,13 +250,18 @@ def __init__(
248250
"""
249251
if elements is None:
250252
elements = []
251-
self._areas: Dict[int, Element] = OrderedDict(
253+
self._areas: Dict[int, Union["Area", "Node", "Relation", "Way"]] = OrderedDict(
252254
(element.id, element) for element in elements if is_valid_type(element, Area)
253255
)
254-
self._nodes = OrderedDict((element.id, element) for element in elements if is_valid_type(element, Node))
255-
self._ways = OrderedDict((element.id, element) for element in elements if is_valid_type(element, Way))
256-
self._relations = OrderedDict((element.id, element)
257-
for element in elements if is_valid_type(element, Relation))
256+
self._nodes = OrderedDict(
257+
(element.id, element) for element in elements if is_valid_type(element, Node)
258+
)
259+
self._ways = OrderedDict(
260+
(element.id, element) for element in elements if is_valid_type(element, Way)
261+
)
262+
self._relations = OrderedDict(
263+
(element.id, element) for element in elements if is_valid_type(element, Relation)
264+
)
258265
self._class_collection_map: Dict[Any, Any] = {
259266
Node: self._nodes,
260267
Way: self._ways,
@@ -275,13 +282,18 @@ def expand(self, other: "Result"):
275282
if not isinstance(other, Result):
276283
raise ValueError("Provided argument has to be instance of overpy:Result()")
277284

278-
other_collection_map = {Node: other.nodes, Way: other.ways, Relation: other.relations, Area: other.areas}
285+
other_collection_map: Dict[Type["Element"], List[Union["Area", "Node", "Relation", "Way"]]] = {
286+
Area: other.areas,
287+
Node: other.nodes,
288+
Relation: other.relations,
289+
Way: other.ways
290+
}
279291
for element_type, own_collection in self._class_collection_map.items():
280292
for element in other_collection_map[element_type]:
281293
if is_valid_type(element, element_type) and element.id not in own_collection:
282294
own_collection[element.id] = element
283295

284-
def append(self, element: "Element"):
296+
def append(self, element: Union["Area", "Node", "Relation", "Way"]):
285297
"""
286298
Append a new element to the result.
287299
@@ -292,7 +304,7 @@ def append(self, element: "Element"):
292304

293305
def get_elements(
294306
self,
295-
filter_cls: ElementTypeVar,
307+
filter_cls: Type[ElementTypeVar],
296308
elem_id: Optional[int] = None) -> List[ElementTypeVar]:
297309
"""
298310
Get a list of elements from the result and filter the element type by a class.
@@ -345,7 +357,7 @@ def from_json(cls, data: dict, api: Optional[Overpass] = None) -> "Result":
345357
:return: New instance of Result object
346358
"""
347359
result = cls(api=api)
348-
elem_cls: Type[Element]
360+
elem_cls: Type[Union["Area", "Node", "Relation", "Way"]]
349361
for elem_cls in [Node, Way, Relation, Area]:
350362
for element in data.get("elements", []):
351363
e_type = element.get("type")
@@ -359,7 +371,7 @@ def from_xml(
359371
cls,
360372
data: Union[str, xml.etree.ElementTree.Element],
361373
api: Optional[Overpass] = None,
362-
parser: Optional[int] = None):
374+
parser: Optional[int] = None) -> "Result":
363375
"""
364376
Create a new instance and load data from xml data or object.
365377
@@ -389,7 +401,7 @@ def from_xml(
389401
else:
390402
raise exception.OverPyException("Unable to detect data type.")
391403

392-
elem_cls: Type[Element]
404+
elem_cls: Type[Union["Area", "Node", "Relation", "Way"]]
393405
for elem_cls in [Node, Way, Relation, Area]:
394406
for child in root:
395407
if child.tag.lower() == elem_cls._type_value:
@@ -409,7 +421,7 @@ def from_xml(
409421
raise Exception("Unknown XML parser")
410422
return result
411423

412-
def get_area(self, area_id: int, resolve_missing: bool = False) -> Type["Area"]:
424+
def get_area(self, area_id: int, resolve_missing: bool = False) -> "Area":
413425
"""
414426
Get an area by its ID.
415427
@@ -442,7 +454,7 @@ def get_area(self, area_id: int, resolve_missing: bool = False) -> Type["Area"]:
442454

443455
return areas[0]
444456

445-
def get_areas(self, area_id: Optional[int] = None) -> List[Type["Area"]]:
457+
def get_areas(self, area_id: Optional[int] = None) -> List["Area"]:
446458
"""
447459
Alias for get_elements() but filter the result by Area
448460
@@ -451,7 +463,7 @@ def get_areas(self, area_id: Optional[int] = None) -> List[Type["Area"]]:
451463
"""
452464
return self.get_elements(Area, elem_id=area_id)
453465

454-
def get_node(self, node_id: int, resolve_missing: bool = False):
466+
def get_node(self, node_id: int, resolve_missing: bool = False) -> "Node":
455467
"""
456468
Get a node by its ID.
457469
@@ -484,7 +496,7 @@ def get_node(self, node_id: int, resolve_missing: bool = False):
484496

485497
return nodes[0]
486498

487-
def get_nodes(self, node_id: Optional[int] = None) -> List[Type["Node"]]:
499+
def get_nodes(self, node_id: Optional[int] = None) -> List["Node"]:
488500
"""
489501
Alias for get_elements() but filter the result by Node()
490502
@@ -494,7 +506,7 @@ def get_nodes(self, node_id: Optional[int] = None) -> List[Type["Node"]]:
494506
"""
495507
return self.get_elements(Node, elem_id=node_id)
496508

497-
def get_relation(self, rel_id: int, resolve_missing: bool = False) -> Type["Relation"]:
509+
def get_relation(self, rel_id: int, resolve_missing: bool = False) -> "Relation":
498510
"""
499511
Get a relation by its ID.
500512
@@ -527,7 +539,7 @@ def get_relation(self, rel_id: int, resolve_missing: bool = False) -> Type["Rela
527539

528540
return relations[0]
529541

530-
def get_relations(self, rel_id: int = None) -> List[Type["Relation"]]:
542+
def get_relations(self, rel_id: int = None) -> List["Relation"]:
531543
"""
532544
Alias for get_elements() but filter the result by Relation
533545
@@ -536,7 +548,7 @@ def get_relations(self, rel_id: int = None) -> List[Type["Relation"]]:
536548
"""
537549
return self.get_elements(Relation, elem_id=rel_id)
538550

539-
def get_way(self, way_id: int, resolve_missing: bool = False) -> Type["Way"]:
551+
def get_way(self, way_id: int, resolve_missing: bool = False) -> "Way":
540552
"""
541553
Get a way by its ID.
542554
@@ -569,7 +581,7 @@ def get_way(self, way_id: int, resolve_missing: bool = False) -> Type["Way"]:
569581

570582
return ways[0]
571583

572-
def get_ways(self, way_id: Optional[int] = None) -> List[Type["Way"]]:
584+
def get_ways(self, way_id: Optional[int] = None) -> List["Way"]:
573585
"""
574586
Alias for get_elements() but filter the result by Way
575587
@@ -643,7 +655,7 @@ def get_center_from_xml_dom(cls, sub_child: xml.etree.ElementTree.Element) -> Tu
643655
return center_lat, center_lon
644656

645657
@classmethod
646-
def from_json(cls, data: dict, result: Optional[Result] = None) -> "Element":
658+
def from_json(cls: Type[ElementTypeVar], data: dict, result: Optional[Result] = None) -> ElementTypeVar:
647659
"""
648660
Create new Element() from json data
649661
:param data:
@@ -653,7 +665,10 @@ def from_json(cls, data: dict, result: Optional[Result] = None) -> "Element":
653665
raise NotImplementedError
654666

655667
@classmethod
656-
def from_xml(cls, child: xml.etree.ElementTree.Element, result: Optional[Result] = None) -> "Element":
668+
def from_xml(
669+
cls: Type[ElementTypeVar],
670+
child: xml.etree.ElementTree.Element,
671+
result: Optional[Result] = None) -> ElementTypeVar:
657672
"""
658673
Create new Element() element from XML data
659674
"""
@@ -898,13 +913,13 @@ def __repr__(self):
898913
return f"<overpy.Way id={self.id} nodes={self._node_ids}>"
899914

900915
@property
901-
def nodes(self) -> List[Type[Node]]:
916+
def nodes(self) -> List[Node]:
902917
"""
903918
List of nodes associated with the way.
904919
"""
905920
return self.get_nodes()
906921

907-
def get_nodes(self, resolve_missing: bool = False) -> List[Type[Node]]:
922+
def get_nodes(self, resolve_missing: bool = False) -> List[Node]:
908923
"""
909924
Get the nodes defining the geometry of the way
910925
@@ -1343,7 +1358,7 @@ def __repr__(self):
13431358
class RelationWay(RelationMember):
13441359
_type_value = "way"
13451360

1346-
def resolve(self, resolve_missing: bool = False) -> Type[Way]:
1361+
def resolve(self, resolve_missing: bool = False) -> Way:
13471362
return self._result.get_way(self.ref, resolve_missing=resolve_missing)
13481363

13491364
def __repr__(self):
@@ -1362,7 +1377,7 @@ def __repr__(self):
13621377
class RelationRelation(RelationMember):
13631378
_type_value = "relation"
13641379

1365-
def resolve(self, resolve_missing: bool = False) -> Type[Relation]:
1380+
def resolve(self, resolve_missing: bool = False) -> Relation:
13661381
return self._result.get_relation(self.ref, resolve_missing=resolve_missing)
13671382

13681383
def __repr__(self):
@@ -1372,7 +1387,7 @@ def __repr__(self):
13721387
class RelationArea(RelationMember):
13731388
_type_value = "area"
13741389

1375-
def resolve(self, resolve_missing: bool = False) -> Type[Area]:
1390+
def resolve(self, resolve_missing: bool = False) -> Area:
13761391
return self._result.get_area(self.ref, resolve_missing=resolve_missing)
13771392

13781393
def __repr__(self):

overpy/exception.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def __init__(self, type_expected, type_provided=None):
3030
self.type_expected = type_expected
3131
self.type_provided = type_provided
3232

33-
def __str__(self):
33+
def __str__(self) -> str:
3434
return "Type expected '{}' but '{}' provided".format(
3535
self.type_expected,
3636
str(self.type_provided)
@@ -45,7 +45,7 @@ def __init__(self, retry_count, exceptions):
4545
self.exceptions = exceptions
4646
self.retry_count = retry_count
4747

48-
def __str__(self):
48+
def __str__(self) -> str:
4949
return "Unable get any result from the Overpass API server after %d retries." % self.retry_count
5050

5151

@@ -64,7 +64,7 @@ def __init__(self, query, msgs=None):
6464
msgs = []
6565
self.msgs = msgs
6666

67-
def __str__(self):
67+
def __str__(self) -> str:
6868
tmp_msgs = []
6969
for tmp_msg in self.msgs:
7070
if not isinstance(tmp_msg, str):
@@ -89,7 +89,7 @@ def __init__(self, msg=None):
8989
#: The message from the remark tag or element
9090
self.msg = msg
9191

92-
def __str__(self):
92+
def __str__(self) -> str:
9393
if self.msg is None:
9494
return "No error message provided"
9595
if not isinstance(self.msg, str):
@@ -139,7 +139,7 @@ class OverpassUnknownContentType(OverPyException):
139139
def __init__(self, content_type):
140140
self.content_type = content_type
141141

142-
def __str__(self):
142+
def __str__(self) -> str:
143143
if self.content_type is None:
144144
return "No content type returned"
145145
return "Unknown content type: %s" % self.content_type
@@ -162,5 +162,5 @@ class OverpassUnknownHTTPStatusCode(OverPyException):
162162
def __init__(self, code):
163163
self.code = code
164164

165-
def __str__(self):
165+
def __str__(self) -> str:
166166
return "Unknown/Unhandled status code: %d" % self.code

overpy/helper.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1+
from typing import List, Optional
12
__author__ = 'mjob'
23

34
import overpy
45

56

6-
def get_street(street, areacode, api=None):
7+
def get_street(
8+
street: str,
9+
areacode: str,
10+
api: Optional[overpy.Overpass] = None) -> overpy.Result:
711
"""
812
Retrieve streets in a given bounding area
913
10-
:param overpy.Overpass api: First street of intersection
11-
:param String street: Name of street
12-
:param String areacode: The OSM id of the bounding area
14+
:param street: Name of street
15+
:param areacode: The OSM id of the bounding area
16+
:param api: API object to fetch missing elements
1317
:return: Parsed result
1418
:raises overpy.exception.OverPyException: If something bad happens.
1519
"""
@@ -35,14 +39,18 @@ def get_street(street, areacode, api=None):
3539
return data
3640

3741

38-
def get_intersection(street1, street2, areacode, api=None):
42+
def get_intersection(
43+
street1: str,
44+
street2: str,
45+
areacode: str,
46+
api: Optional[overpy.Overpass] = None) -> List[overpy.Node]:
3947
"""
4048
Retrieve intersection of two streets in a given bounding area
4149
42-
:param overpy.Overpass api: First street of intersection
43-
:param String street1: Name of first street of intersection
44-
:param String street2: Name of second street of intersection
45-
:param String areacode: The OSM id of the bounding area
50+
:param street1: Name of first street of intersection
51+
:param street2: Name of second street of intersection
52+
:param areacode: The OSM id of the bounding area
53+
:param api: API object to fetch missing elements
4654
:return: List of intersections
4755
:raises overpy.exception.OverPyException: If something bad happens.
4856
"""

0 commit comments

Comments
 (0)