From 357db1eaaf4036d830d27cc6291efeea9dfd613e Mon Sep 17 00:00:00 2001 From: PhiBo Date: Fri, 17 Mar 2017 23:39:40 +0100 Subject: [PATCH 1/7] src - Handle remark tags and elements --- overpy/__init__.py | 12 ++++++++++++ overpy/exception.py | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/overpy/__init__.py b/overpy/__init__.py index 78072e9..18b3697 100644 --- a/overpy/__init__.py +++ b/overpy/__init__.py @@ -84,6 +84,12 @@ def __init__(self, read_chunk_size=None, url=None, xml_parser=XML_PARSER_SAX, ma self.xml_parser = xml_parser + def _handle_remark_msg(self, msg): + msg = msg.strip() + if msg.startswith("runtime error:"): + raise exception.OverpassRuntimeError(msg) + raise exception.OverpassUnknownError(msg) + def query(self, query): """ Query the Overpass API @@ -189,6 +195,8 @@ def parse_json(self, data, encoding="utf-8"): if isinstance(data, bytes): data = data.decode(encoding) data = json.loads(data, parse_float=Decimal) + if "remark" in data: + self._handle_remark_msg(msg=data.get("remark")) return Result.from_json(data, api=self) def parse_xml(self, data, encoding="utf-8", parser=None): @@ -210,6 +218,10 @@ def parse_xml(self, data, encoding="utf-8", parser=None): # Python 2.x: Convert unicode strings data = data.encode(encoding) + m = re.compile("(?P[^<>]*)").search(data) + if m: + self._handle_remark_msg(m.group("msg")) + return Result.from_xml(data, api=self, parser=parser) diff --git a/overpy/exception.py b/overpy/exception.py index c529364..6ef3895 100644 --- a/overpy/exception.py +++ b/overpy/exception.py @@ -74,6 +74,10 @@ def __str__(self): return "\n".join(tmp_msgs) +class OverpassError(OverPyException): + pass + + class OverpassGatewayTimeout(OverPyException): """ Raised if load of the Overpass API service is too high and it can't handle the request. @@ -82,6 +86,14 @@ def __init__(self): OverPyException.__init__(self, "Server load too high") +class OverpassRuntimeError(OverpassError): + """ + Raised if the server returns a remark-tag(xml) or remark element(json) with a message starting with + 'runtime error: '. + """ + pass + + class OverpassTooManyRequests(OverPyException): """ Raised if the Overpass API service returns a 429 status code. @@ -106,6 +118,13 @@ def __str__(self): return "Unknown content type: %s" % self.content_type +class OverpassUnknownError(OverpassError): + """ + Raised if the server returns a remark-tag(xml) or remark element(json) and we are unable to find any reason. + """ + pass + + class OverpassUnknownHTTPStatusCode(OverPyException): """ Raised if the returned HTTP status code isn't handled by OverPy. From 6e4436e33264c492c57a086e61e3c96d6339644a Mon Sep 17 00:00:00 2001 From: PhiBo Date: Fri, 17 Mar 2017 23:40:38 +0100 Subject: [PATCH 2/7] test - Test handling of remark tags and elements --- tests/json/remark-runtime-error-01.json | 15 +++++++++++++++ tests/test_json.py | 9 ++++++++- tests/test_xml.py | 7 +++++++ tests/xml/remark-runtime-error-01.xml | 8 ++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/json/remark-runtime-error-01.json create mode 100644 tests/xml/remark-runtime-error-01.xml diff --git a/tests/json/remark-runtime-error-01.json b/tests/json/remark-runtime-error-01.json new file mode 100644 index 0000000..83b54cb --- /dev/null +++ b/tests/json/remark-runtime-error-01.json @@ -0,0 +1,15 @@ +{ + "version": 0.6, + "generator": "Overpass API", + "osm3s": { + "timestamp_osm_base": "2017-03-17T22:05:02Z", + "timestamp_areas_base": "2017-03-17T18:38:02Z", + "copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL." + }, + "elements": [ + + + + ], +"remark": "runtime error: Query timed out in \"query\" at line 4 after 2 seconds." +} diff --git a/tests/test_json.py b/tests/test_json.py index 60a1a0a..50cf630 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -98,4 +98,11 @@ def test_element_wrong_type(self): { "type": "foo" } - ) \ No newline at end of file + ) + + +class TestRemark(object): + def test_remark_runtime_error(self): + api = overpy.Overpass() + with pytest.raises(overpy.exception.OverpassRuntimeError): + api.parse_json(read_file("json/remark-runtime-error-01.json")) diff --git a/tests/test_xml.py b/tests/test_xml.py index c25e836..3de33ac 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -169,3 +169,10 @@ def test_way_missing_data(self): node = ET.fromstring(data) with pytest.raises(ValueError): overpy.Way.from_xml(node) + + +class TestRemark(object): + def test_remark_runtime_error(self): + api = overpy.Overpass() + with pytest.raises(overpy.exception.OverpassRuntimeError): + api.parse_xml(read_file("xml/remark-runtime-error-01.xml")) diff --git a/tests/xml/remark-runtime-error-01.xml b/tests/xml/remark-runtime-error-01.xml new file mode 100644 index 0000000..5aa0888 --- /dev/null +++ b/tests/xml/remark-runtime-error-01.xml @@ -0,0 +1,8 @@ + + +The data included in this document is from www.openstreetmap.org. The data is made available under ODbL. + + + runtime error: Query timed out in "query" at line 4 after 2 seconds. + + From 2736d8f3fa9833bc950074ddf3833602167685f7 Mon Sep 17 00:00:00 2001 From: PhiBo Date: Sat, 18 Mar 2017 07:22:37 +0100 Subject: [PATCH 3/7] src - Add docstrings --- overpy/__init__.py | 7 +++++++ overpy/exception.py | 3 +++ 2 files changed, 10 insertions(+) diff --git a/overpy/__init__.py b/overpy/__init__.py index 18b3697..bdfc1c6 100644 --- a/overpy/__init__.py +++ b/overpy/__init__.py @@ -85,6 +85,13 @@ def __init__(self, read_chunk_size=None, url=None, xml_parser=XML_PARSER_SAX, ma self.xml_parser = xml_parser def _handle_remark_msg(self, msg): + """ + Try to parse the message provided with the remark tag or element. + + :param str msg: The message + :raises overpy.exception.OverpassRuntimeError: If message starts with 'runtime error:' + :raises overpy.exception.OverpassUnknownError: If it is unable to identify the error + """ msg = msg.strip() if msg.startswith("runtime error:"): raise exception.OverpassRuntimeError(msg) diff --git a/overpy/exception.py b/overpy/exception.py index 6ef3895..d1503fe 100644 --- a/overpy/exception.py +++ b/overpy/exception.py @@ -75,6 +75,9 @@ def __str__(self): class OverpassError(OverPyException): + """ + Base exception to report errors if the response returns a remark tag or element. + """ pass From c7f2e50f7cd43190d5d71b1ca25b12a70b42e028 Mon Sep 17 00:00:00 2001 From: PhiBo Date: Fri, 7 Apr 2017 12:33:32 +0200 Subject: [PATCH 4/7] src - Improve remark handling - Add additional exceptions - Add msg value from remark tag or element - Add additional documentation --- overpy/__init__.py | 9 ++++++--- overpy/exception.py | 26 ++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/overpy/__init__.py b/overpy/__init__.py index bdfc1c6..13de583 100644 --- a/overpy/__init__.py +++ b/overpy/__init__.py @@ -90,12 +90,15 @@ def _handle_remark_msg(self, msg): :param str msg: The message :raises overpy.exception.OverpassRuntimeError: If message starts with 'runtime error:' - :raises overpy.exception.OverpassUnknownError: If it is unable to identify the error + :raises overpy.exception.OverpassRuntimeRemark: If message starts with 'runtime remark:' + :raises overpy.exception.OverpassUnknownError: If we are unable to identify the error """ msg = msg.strip() if msg.startswith("runtime error:"): - raise exception.OverpassRuntimeError(msg) - raise exception.OverpassUnknownError(msg) + raise exception.OverpassRuntimeError(msg=msg) + elif msg.startswith("runtime remark:"): + raise exception.OverpassRuntimeRemark(msg=msg) + raise exception.OverpassUnknownError(msg=msg) def query(self, query): """ diff --git a/overpy/exception.py b/overpy/exception.py index d1503fe..4351c80 100644 --- a/overpy/exception.py +++ b/overpy/exception.py @@ -77,8 +77,22 @@ def __str__(self): class OverpassError(OverPyException): """ Base exception to report errors if the response returns a remark tag or element. + + .. note:: + If you are not sure which of the subexceptions you should use, use this one and try to parse the message. + + For more information have a look at https://github.com/DinoTools/python-overpy/issues/62 + + :param str msg: The message from the remark tag or element """ - pass + def __init__(self, msg=None): + #: The message from the remark tag or element + self.msg = msg + + def __str__(self): + if self.msg is None: + return "No error message provided" + return self.msg class OverpassGatewayTimeout(OverPyException): @@ -92,7 +106,15 @@ def __init__(self): class OverpassRuntimeError(OverpassError): """ Raised if the server returns a remark-tag(xml) or remark element(json) with a message starting with - 'runtime error: '. + 'runtime error:'. + """ + pass + + +class OverpassRuntimeRemark(OverpassError): + """ + Raised if the server returns a remark-tag(xml) or remark element(json) with a message starting with + 'runtime remark:'. """ pass From bd802d6d49654128b6c3f584be2d044f05fd559c Mon Sep 17 00:00:00 2001 From: PhiBo Date: Fri, 7 Apr 2017 12:34:22 +0200 Subject: [PATCH 5/7] test - More remark tests --- tests/json/remark-runtime-remark-01.json | 15 +++++++++++++++ tests/json/remark-unknown-01.json | 15 +++++++++++++++ tests/test_json.py | 10 ++++++++++ tests/test_xml.py | 10 ++++++++++ tests/xml/remark-runtime-remark-01.xml | 8 ++++++++ tests/xml/remark-unknown-01.xml | 8 ++++++++ 6 files changed, 66 insertions(+) create mode 100644 tests/json/remark-runtime-remark-01.json create mode 100644 tests/json/remark-unknown-01.json create mode 100644 tests/xml/remark-runtime-remark-01.xml create mode 100644 tests/xml/remark-unknown-01.xml diff --git a/tests/json/remark-runtime-remark-01.json b/tests/json/remark-runtime-remark-01.json new file mode 100644 index 0000000..fc21c88 --- /dev/null +++ b/tests/json/remark-runtime-remark-01.json @@ -0,0 +1,15 @@ +{ + "version": 0.6, + "generator": "Overpass API", + "osm3s": { + "timestamp_osm_base": "2017-03-17T22:05:02Z", + "timestamp_areas_base": "2017-03-17T18:38:02Z", + "copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL." + }, + "elements": [ + + + + ], +"remark": "runtime remark: Test" +} diff --git a/tests/json/remark-unknown-01.json b/tests/json/remark-unknown-01.json new file mode 100644 index 0000000..815b770 --- /dev/null +++ b/tests/json/remark-unknown-01.json @@ -0,0 +1,15 @@ +{ + "version": 0.6, + "generator": "Overpass API", + "osm3s": { + "timestamp_osm_base": "2017-03-17T22:05:02Z", + "timestamp_areas_base": "2017-03-17T18:38:02Z", + "copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL." + }, + "elements": [ + + + + ], +"remark": "Test remark" +} diff --git a/tests/test_json.py b/tests/test_json.py index 50cf630..287250a 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -106,3 +106,13 @@ def test_remark_runtime_error(self): api = overpy.Overpass() with pytest.raises(overpy.exception.OverpassRuntimeError): api.parse_json(read_file("json/remark-runtime-error-01.json")) + + def test_remark_runtime_remark(self): + api = overpy.Overpass() + with pytest.raises(overpy.exception.OverpassRuntimeRemark): + api.parse_json(read_file("json/remark-runtime-remark-01.json")) + + def test_remark_unknown(self): + api = overpy.Overpass() + with pytest.raises(overpy.exception.OverpassUnknownError): + api.parse_json(read_file("json/remark-unknown-01.json")) \ No newline at end of file diff --git a/tests/test_xml.py b/tests/test_xml.py index 3de33ac..d81f003 100644 --- a/tests/test_xml.py +++ b/tests/test_xml.py @@ -176,3 +176,13 @@ def test_remark_runtime_error(self): api = overpy.Overpass() with pytest.raises(overpy.exception.OverpassRuntimeError): api.parse_xml(read_file("xml/remark-runtime-error-01.xml")) + + def test_remark_runtime_remark(self): + api = overpy.Overpass() + with pytest.raises(overpy.exception.OverpassRuntimeRemark): + api.parse_xml(read_file("xml/remark-runtime-remark-01.xml")) + + def test_remark_unknown(self): + api = overpy.Overpass() + with pytest.raises(overpy.exception.OverpassUnknownError): + api.parse_xml(read_file("xml/remark-unknown-01.xml")) diff --git a/tests/xml/remark-runtime-remark-01.xml b/tests/xml/remark-runtime-remark-01.xml new file mode 100644 index 0000000..254fe97 --- /dev/null +++ b/tests/xml/remark-runtime-remark-01.xml @@ -0,0 +1,8 @@ + + +The data included in this document is from www.openstreetmap.org. The data is made available under ODbL. + + + runtime remark: Test + + diff --git a/tests/xml/remark-unknown-01.xml b/tests/xml/remark-unknown-01.xml new file mode 100644 index 0000000..ad8a047 --- /dev/null +++ b/tests/xml/remark-unknown-01.xml @@ -0,0 +1,8 @@ + + +The data included in this document is from www.openstreetmap.org. The data is made available under ODbL. + + + Test remark + + From 31c6e689c0d49d6617e020597914f47a0bc98f04 Mon Sep 17 00:00:00 2001 From: PhiBo Date: Fri, 7 Apr 2017 12:41:55 +0200 Subject: [PATCH 6/7] src - OverpassError handle none string values --- overpy/exception.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/overpy/exception.py b/overpy/exception.py index 4351c80..3d8416a 100644 --- a/overpy/exception.py +++ b/overpy/exception.py @@ -92,6 +92,8 @@ def __init__(self, msg=None): def __str__(self): if self.msg is None: return "No error message provided" + if not isinstance(self.msg, str): + return str(self.msg) return self.msg From 61de24e34292f9f42eafa76b600b195c06a8f450 Mon Sep 17 00:00:00 2001 From: PhiBo Date: Fri, 7 Apr 2017 12:42:30 +0200 Subject: [PATCH 7/7] test - Test OverpassError and child exceptions --- tests/test_exception.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/test_exception.py b/tests/test_exception.py index 0c79064..4b4dd18 100644 --- a/tests/test_exception.py +++ b/tests/test_exception.py @@ -39,4 +39,26 @@ def test_overpass_unknown_content_type(self): def test_overpass_unknown_http_status_code(self): e = overpy.exception.OverpassUnknownHTTPStatusCode(123) assert e.code == 123 - assert str(e).endswith("123") \ No newline at end of file + assert str(e).endswith("123") + + def test_overpass_error(self): + exceptions = [ + overpy.exception.OverpassError, + overpy.exception.OverpassRuntimeError, + overpy.exception.OverpassRuntimeRemark, + overpy.exception.OverpassUnknownError + ] + for cls in exceptions: + e = cls(msg="Test message") + assert e.msg == "Test message" + assert str(e) == "Test message" + + for cls in exceptions: + e = cls() + assert e.msg is None + assert str(e) == "No error message provided" + + for cls in exceptions: + e = cls(msg=123) + assert e.msg == 123 + assert str(e) == "123"