Skip to content
Merged
34 changes: 30 additions & 4 deletions overpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ class Way(Element):

_type_value = "way"

def __init__(self, way_id=None, node_ids=None, **kwargs):
def __init__(self, way_id=None, center_lat=None, center_lon=None, node_ids=None, **kwargs):
"""
:param node_ids: List of node IDs
:type node_ids: List or Tuple
Expand All @@ -627,6 +627,10 @@ def __init__(self, way_id=None, node_ids=None, **kwargs):

#: List of Ids of the associated nodes
self._node_ids = node_ids

#: The lat/lon of the center of the way (optional depending on query)
self.center_lat = center_lat
self.center_lon = center_lon

def __repr__(self):
return "<overpy.Way id={} nodes={}>".format(self.id, self._node_ids)
Expand Down Expand Up @@ -750,6 +754,8 @@ def from_xml(cls, child, result=None):

tags = {}
node_ids = []
center_lat = None
center_lon = None

for sub_child in child:
if sub_child.tag.lower() == "tag":
Expand All @@ -764,6 +770,11 @@ def from_xml(cls, child, result=None):
raise ValueError("Unable to find required ref value.")
ref_id = int(ref_id)
node_ids.append(ref_id)
if sub_child.tag.lower() == "center":
center_lat = Decimal(sub_child.attrib.get("lat"))
center_lon = Decimal(sub_child.attrib.get("lon"))
if center_lat is None or center_lon is None:
raise ValueError("Unable to get lat/lon of way center.")

way_id = child.attrib.get("id")
if way_id is not None:
Expand All @@ -776,7 +787,8 @@ def from_xml(cls, child, result=None):
continue
attributes[n] = v

return cls(way_id=way_id, attributes=attributes, node_ids=node_ids, tags=tags, result=result)
return cls(way_id=way_id, center_lat=center_lat, center_lon=center_lon,
attributes=attributes, node_ids=node_ids, tags=tags, result=result)


class Relation(Element):
Expand Down Expand Up @@ -1009,7 +1021,7 @@ class OSMSAXHandler(handler.ContentHandler):
#: Tuple of opening elements to ignore
ignore_start = ('osm', 'meta', 'note', 'bounds', 'remark')
#: Tuple of closing elements to ignore
ignore_end = ('osm', 'meta', 'note', 'bounds', 'remark', 'tag', 'nd', 'member')
ignore_end = ('osm', 'meta', 'note', 'bounds', 'remark', 'tag', 'nd', 'member', 'center')

def __init__(self, result):
"""
Expand Down Expand Up @@ -1049,9 +1061,21 @@ def endElement(self, name):
try:
handler = getattr(self, '_handle_end_%s' % name)
except AttributeError:
raise KeyError("Unknown element start '%s'" % name)
raise KeyError("Unknown element end '%s'" % name)
handler()

def _handle_start_center(self, attrs):
"""
Handle opening center element

:param attrs: Attributes of the element
:type attrs: Dict
"""
if attrs.get('lat', None) is not None:
self._curr['center_lat'] = Decimal(attrs['lat'])
if attrs.get('lon', None) is not None:
self._curr['center_lon'] = Decimal(attrs['lon'])

def _handle_start_tag(self, attrs):
"""
Handle opening tag element
Expand Down Expand Up @@ -1104,6 +1128,8 @@ def _handle_start_way(self, attrs):
:type attrs: Dict
"""
self._curr = {
'center_lat': None,
'center_lon': None,
'attributes': dict(attrs),
'node_ids': [],
'tags': {},
Expand Down
57 changes: 56 additions & 1 deletion tests/base_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,4 +289,59 @@ def _test_way02(self, result):
# way_ids is an alias for get_way_ids() and should return the same data
for way_ids in (result.way_ids, result.get_way_ids()):
assert len(way_ids) == 1
assert way_ids[0] == 317146077
assert way_ids[0] == 317146077

def _test_way03(self, result):
assert len(result.nodes) == 6
assert len(result.relations) == 0
assert len(result.ways) == 1

way = result.ways[0]

assert isinstance(way, overpy.Way)
assert isinstance(way.id, int)
assert way.id == 317146077

assert isinstance(way.tags, dict)
assert len(way.tags) == 1
assert way.tags["building"] == "yes"

assert isinstance(way.center_lat, Decimal)
assert isinstance(way.center_lon, Decimal)
assert way.center_lat == Decimal("50.7494852")
assert way.center_lon == Decimal("7.1757466")

nodes = way.nodes

assert len(nodes) == 7

node = nodes[0]

assert isinstance(node, overpy.Node)
assert node.id == 3233854241

# try to get a single way by id
way = result.get_way(317146077)
assert way.id == 317146077

# try to get a single way by id not available in the result
with pytest.raises(overpy.exception.DataIncomplete):
result.get_way(123456)

# node_ids is an alias for get_node_ids() and should return the same data
for node_ids in (result.node_ids, result.get_node_ids()):
assert len(node_ids) == 6
assert node_ids[0] == 3233854233
assert node_ids[1] == 3233854234
assert node_ids[2] == 3233854236
assert node_ids[3] == 3233854237
assert node_ids[4] == 3233854238
assert node_ids[5] == 3233854241

assert len(result.relation_ids) == 0
assert len(result.get_relation_ids()) == 0

# way_ids is an alias for get_way_ids() and should return the same data
for way_ids in (result.way_ids, result.get_way_ids()):
assert len(way_ids) == 1
assert way_ids[0] == 317146077
9 changes: 9 additions & 0 deletions tests/test_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ def test_way02(self):
result = api.parse_xml(read_file("xml/way-02.xml"), parser=overpy.XML_PARSER_SAX)
self._test_way02(result)

def test_way03(self):
api = overpy.Overpass()
# DOM
result = api.parse_xml(read_file("xml/way-03.xml"), parser=overpy.XML_PARSER_DOM)
self._test_way03(result)
# SAX
result = api.parse_xml(read_file("xml/way-03.xml"), parser=overpy.XML_PARSER_SAX)
self._test_way03(result)


class TestDataError(object):
def _get_element_wrong_type(self):
Expand Down
24 changes: 24 additions & 0 deletions tests/xml/way-03.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="Overpass API">
<note>The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.</note>
<meta osm_base="2016-04-13T17:17:02Z"/>

<node id="3233854233" lat="50.7494187" lon="7.1758731"/>
<node id="3233854234" lat="50.7494236" lon="7.1757664"/>
<node id="3233854236" lat="50.7494909" lon="7.1757741"/>
<node id="3233854237" lat="50.7494985" lon="7.1756064"/>
<node id="3233854238" lat="50.7495391" lon="7.1758868"/>
<node id="3233854241" lat="50.7495516" lon="7.1756125"/>
<way id="317146077">
<center lat="50.7494852" lon="7.1757466"/>
<nd ref="3233854241"/>
<nd ref="3233854238"/>
<nd ref="3233854233"/>
<nd ref="3233854234"/>
<nd ref="3233854236"/>
<nd ref="3233854237"/>
<nd ref="3233854241"/>
<tag k="building" v="yes"/>
</way>

</osm>