You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

overpy

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

overpy - pypi Package Compare versions

Comparing version
0.4
to
0.5
+11
docs/source/faq.rst
Frequently Asked Questions
==========================
429 Too Many Requests
---------------------
If too many requests are send from the same IP address the server blocks some requests to avoid that a user uses up all resources.
For more information have a look at the `Overpass API documentation <http://overpass-api.de/command_line.html>`_.
OverPy tries to fetch missing information automatically.
To limit the number of requests you should try to fetch all required information/data(relations, ways, nodes, tags, ...) with the initial query.
{
"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."
}
{
"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"
}
{
"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"
}
<?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="2017-03-17T22:03:02Z" areas="2017-03-17T18:38:02Z"/>
<remark> runtime error: Query timed out in "query" at line 4 after 2 seconds. </remark>
</osm>
<?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="2017-03-17T22:03:02Z" areas="2017-03-17T18:38:02Z"/>
<remark> runtime remark: Test </remark>
</osm>
<?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="2017-03-17T22:03:02Z" areas="2017-03-17T18:38:02Z"/>
<remark> Test remark </remark>
</osm>
+12
-0

@@ -9,2 +9,14 @@ Changelog

0.5 (2021-04-14)
~~~~~~~~~~~~~~~~
* Add support to retry a failed request
* Improve test handlers to fix issues with Py2.7 and PyPy
* Improve tests
* Add Support for Python 3.6
* Add function to handle remark tags and elements
* Add support to parse data from ET.Element
* Move attribute modifiers from class to package
* Change to use Exception instead of BaseException
0.4 (2016-12-08)

@@ -11,0 +23,0 @@ ~~~~~~~~~~~~~~~~

+1
-1

@@ -11,2 +11,3 @@ Welcome to Python Overpass API's documentation!

example
faq
api

@@ -22,2 +23,1 @@ contributing

* :ref:`search`
Metadata-Version: 1.1
Name: overpy
Version: 0.4
Version: 0.5
Summary: Python Wrapper to access the OpenStreepMap Overpass API

@@ -16,7 +16,7 @@ Home-page: https://github.com/DinoTools/python-overpy

.. image:: https://pypip.in/version/overpy/badge.svg
.. image:: https://img.shields.io/pypi/v/overpy.svg
:target: https://pypi.python.org/pypi/overpy/
:alt: Latest Version
.. image:: https://pypip.in/license/overpy/badge.svg
.. image:: https://img.shields.io/pypi/l/overpy.svg
:target: https://pypi.python.org/pypi/overpy/

@@ -123,3 +123,4 @@ :alt: License

Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy

@@ -13,2 +13,3 @@ CHANGELOG.rst

docs/source/example.rst
docs/source/faq.rst
docs/source/index.rst

@@ -42,2 +43,5 @@ docs/source/introduction.rst

tests/json/relation-04.json
tests/json/remark-runtime-error-01.json
tests/json/remark-runtime-remark-01.json
tests/json/remark-unknown-01.json
tests/json/result-expand-01.json

@@ -60,2 +64,5 @@ tests/json/result-expand-02.json

tests/xml/relation-04.xml
tests/xml/remark-runtime-error-01.xml
tests/xml/remark-runtime-remark-01.xml
tests/xml/remark-unknown-01.xml
tests/xml/way-01.xml

@@ -62,0 +69,0 @@ tests/xml/way-02.xml

@@ -16,3 +16,3 @@ __all__ = [

__version__ = "0.4"
__version__ = "0.5"

@@ -23,2 +23,2 @@ __author__ = "PhiBo (DinoTools)"

__license__ = "MIT"
__copyright__ = "Copyright 2014-2016 %s" % __author__
__copyright__ = "Copyright 2014-2021 %s" % __author__

@@ -8,2 +8,3 @@ from collections import OrderedDict

import sys
import time

@@ -22,2 +23,12 @@ from overpy import exception

# Try to convert some common attributes
# http://wiki.openstreetmap.org/wiki/Elements#Common_attributes
GLOBAL_ATTRIBUTE_MODIFIERS = {
"changeset": int,
"timestamp": lambda ts: datetime.strptime(ts, "%Y-%m-%dT%H:%M:%SZ"),
"uid": int,
"version": int,
"visible": lambda v: v.lower() == "true"
}
if PY2:

@@ -46,7 +57,12 @@ from urllib2 import urlopen

Class to access the Overpass API
:cvar default_max_retry_count: Global max number of retries (Default: 0)
:cvar default_retry_timeout: Global time to wait between tries (Default: 1.0s)
"""
default_max_retry_count = 0
default_read_chunk_size = 4096
default_retry_timeout = 1.0
default_url = "http://overpass-api.de/api/interpreter"
def __init__(self, read_chunk_size=None, url=None, xml_parser=XML_PARSER_SAX):
def __init__(self, read_chunk_size=None, url=None, xml_parser=XML_PARSER_SAX, max_retry_count=None, retry_timeout=None):
"""

@@ -59,2 +75,6 @@ :param read_chunk_size: Max size of each chunk read from the server response

:type xml_parser: Integer
:param max_retry_count: Max number of retries (Default: default_max_retry_count)
:type max_retry_count: Integer
:param retry_timeout: Time to wait between tries (Default: default_retry_timeout)
:type retry_timeout: float
"""

@@ -70,4 +90,29 @@ self.url = self.default_url

self.read_chunk_size = read_chunk_size
if max_retry_count is None:
max_retry_count = self.default_max_retry_count
self.max_retry_count = max_retry_count
if retry_timeout is None:
retry_timeout = self.default_retry_timeout
self.retry_timeout = retry_timeout
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.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=msg)
elif msg.startswith("runtime remark:"):
raise exception.OverpassRuntimeRemark(msg=msg)
raise exception.OverpassUnknownError(msg=msg)
def query(self, query):

@@ -84,53 +129,82 @@ """

try:
f = urlopen(self.url, query)
except HTTPError as e:
f = e
retry_num = 0
retry_exceptions = []
do_retry = True if self.max_retry_count > 0 else False
while retry_num <= self.max_retry_count:
if retry_num > 0:
time.sleep(self.retry_timeout)
retry_num += 1
try:
f = urlopen(self.url, query)
except HTTPError as e:
f = e
response = f.read(self.read_chunk_size)
while True:
data = f.read(self.read_chunk_size)
if len(data) == 0:
break
response = response + data
f.close()
response = f.read(self.read_chunk_size)
while True:
data = f.read(self.read_chunk_size)
if len(data) == 0:
break
response = response + data
f.close()
if f.code == 200:
if PY2:
http_info = f.info()
content_type = http_info.getheader("content-type")
else:
content_type = f.getheader("Content-Type")
if f.code == 200:
if PY2:
http_info = f.info()
content_type = http_info.getheader("content-type")
else:
content_type = f.getheader("Content-Type")
if content_type == "application/json":
return self.parse_json(response)
if content_type == "application/json":
return self.parse_json(response)
if content_type == "application/osm3s+xml":
return self.parse_xml(response)
if content_type == "application/osm3s+xml":
return self.parse_xml(response)
raise exception.OverpassUnknownContentType(content_type)
e = exception.OverpassUnknownContentType(content_type)
if not do_retry:
raise e
retry_exceptions.append(e)
continue
if f.code == 400:
msgs = []
for msg in self._regex_extract_error_msg.finditer(response):
tmp = self._regex_remove_tag.sub(b"", msg.group("msg"))
try:
tmp = tmp.decode("utf-8")
except UnicodeDecodeError:
tmp = repr(tmp)
msgs.append(tmp)
if f.code == 400:
msgs = []
for msg in self._regex_extract_error_msg.finditer(response):
tmp = self._regex_remove_tag.sub(b"", msg.group("msg"))
try:
tmp = tmp.decode("utf-8")
except UnicodeDecodeError:
tmp = repr(tmp)
msgs.append(tmp)
raise exception.OverpassBadRequest(
query,
msgs=msgs
)
e = exception.OverpassBadRequest(
query,
msgs=msgs
)
if not do_retry:
raise e
retry_exceptions.append(e)
continue
if f.code == 429:
raise exception.OverpassTooManyRequests
if f.code == 429:
e = exception.OverpassTooManyRequests
if not do_retry:
raise e
retry_exceptions.append(e)
continue
if f.code == 504:
raise exception.OverpassGatewayTimeout
if f.code == 504:
e = exception.OverpassGatewayTimeout
if not do_retry:
raise e
retry_exceptions.append(e)
continue
raise exception.OverpassUnknownHTTPStatusCode(f.code)
e = exception.OverpassUnknownHTTPStatusCode(f.code)
if not do_retry:
raise e
retry_exceptions.append(e)
continue
raise exception.MaxRetriesReached(retry_count=retry_num, exceptions=retry_exceptions)
def parse_json(self, data, encoding="utf-8"):

@@ -150,2 +224,4 @@ """

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)

@@ -172,2 +248,6 @@

m = re.compile("<remark>(?P<msg>[^<>]*)</remark>").search(data)
if m:
self._handle_remark_msg(m.group("msg"))
return Result.from_xml(data, api=self, parser=parser)

@@ -290,19 +370,35 @@

@classmethod
def from_xml(cls, data, api=None, parser=XML_PARSER_SAX):
def from_xml(cls, data, api=None, parser=None):
"""
Create a new instance and load data from xml object.
Create a new instance and load data from xml data or object.
.. note::
If parser is set to None, the functions tries to find the best parse.
By default the SAX parser is chosen if a string is provided as data.
The parser is set to DOM if an xml.etree.ElementTree.Element is provided as data value.
:param data: Root element
:type data: xml.etree.ElementTree.Element
:param api:
:type data: str | xml.etree.ElementTree.Element
:param api: The instance to query additional information if required.
:type api: Overpass
:param parser: Specify the parser to use(DOM or SAX)
:type parser: Integer
:param parser: Specify the parser to use(DOM or SAX)(Default: None = autodetect, defaults to SAX)
:type parser: Integer | None
:return: New instance of Result object
:rtype: Result
"""
if parser is None:
if isinstance(data, str):
parser = XML_PARSER_SAX
else:
parser = XML_PARSER_DOM
result = cls(api=api)
if parser == XML_PARSER_DOM:
import xml.etree.ElementTree as ET
root = ET.fromstring(data)
if isinstance(data, str):
root = ET.fromstring(data)
elif isinstance(data, ET.Element):
root = data
else:
raise exception.OverPyException("Unable to detect data type.")

@@ -534,13 +630,6 @@ for elem_cls in [Node, Way, Relation, Area]:

self._result = result
# Try to convert some common attributes
# http://wiki.openstreetmap.org/wiki/Elements#Common_attributes
self._attribute_modifiers = {
"changeset": int,
"timestamp": lambda ts: datetime.strptime(ts, "%Y-%m-%dT%H:%M:%SZ"),
"uid": int,
"version": int,
"visible": lambda v: v.lower() == "true"
}
self.attributes = attributes
for n, m in self._attribute_modifiers.items():
# ToDo: Add option to modify attribute modifiers
attribute_modifiers = dict(GLOBAL_ATTRIBUTE_MODIFIERS.items())
for n, m in attribute_modifiers.items():
if n in self.attributes:

@@ -547,0 +636,0 @@ self.attributes[n] = m(self.attributes[n])

@@ -1,2 +0,2 @@

class OverPyException(BaseException):
class OverPyException(Exception):
"""OverPy base exception"""

@@ -40,2 +40,14 @@ pass

class MaxRetriesReached(OverPyException):
"""
Raised if max retries reached and the Overpass server didn't respond with a result.
"""
def __init__(self, retry_count, exceptions):
self.exceptions = exceptions
self.retry_count = retry_count
def __str__(self):
return "Unable get any result from the Overpass API server after %d retries." % self.retry_count
class OverpassBadRequest(OverPyException):

@@ -66,2 +78,25 @@ """

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
"""
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"
if not isinstance(self.msg, str):
return str(self.msg)
return self.msg
class OverpassGatewayTimeout(OverPyException):

@@ -75,2 +110,18 @@ """

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 OverpassRuntimeRemark(OverpassError):
"""
Raised if the server returns a remark-tag(xml) or remark element(json) with a message starting with
'runtime remark:'.
"""
pass
class OverpassTooManyRequests(OverPyException):

@@ -100,2 +151,9 @@ """

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):

@@ -112,2 +170,2 @@ """

def __str__(self):
return "Unknown/Unhandled status code: %d" % self.code
return "Unknown/Unhandled status code: %d" % self.code
Metadata-Version: 1.1
Name: overpy
Version: 0.4
Version: 0.5
Summary: Python Wrapper to access the OpenStreepMap Overpass API

@@ -16,7 +16,7 @@ Home-page: https://github.com/DinoTools/python-overpy

.. image:: https://pypip.in/version/overpy/badge.svg
.. image:: https://img.shields.io/pypi/v/overpy.svg
:target: https://pypi.python.org/pypi/overpy/
:alt: Latest Version
.. image:: https://pypip.in/license/overpy/badge.svg
.. image:: https://img.shields.io/pypi/l/overpy.svg
:target: https://pypi.python.org/pypi/overpy/

@@ -123,3 +123,4 @@ :alt: License

Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy

@@ -8,7 +8,7 @@ Python Overpass Wrapper

.. image:: https://pypip.in/version/overpy/badge.svg
.. image:: https://img.shields.io/pypi/v/overpy.svg
:target: https://pypi.python.org/pypi/overpy/
:alt: Latest Version
.. image:: https://pypip.in/license/overpy/badge.svg
.. image:: https://img.shields.io/pypi/l/overpy.svg
:target: https://pypi.python.org/pypi/overpy/

@@ -15,0 +15,0 @@ :alt: License

@@ -13,3 +13,2 @@ [metadata]

tag_date = 0
tag_svn_revision = 0

@@ -42,2 +42,3 @@ #!/usr/bin/env python

"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: Implementation :: CPython",

@@ -48,3 +49,3 @@ "Programming Language :: Python :: Implementation :: PyPy"

install_requires=[],
packages=find_packages(exclude=["*.tests", "*.tests.*"]),
packages=find_packages(exclude=["*.tests", "*.tests.*", "tests"]),
include_package_data=True,

@@ -51,0 +52,0 @@ package_data={

import os
import sys
import time
from multiprocessing import Process
import threading
from threading import Lock

@@ -9,5 +8,7 @@

if PY2:
from SocketServer import TCPServer, BaseRequestHandler
from SocketServer import BaseRequestHandler, TCPServer, ThreadingMixIn
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
else:
from socketserver import TCPServer, BaseRequestHandler
from socketserver import BaseRequestHandler, TCPServer, ThreadingMixIn
from http.server import BaseHTTPRequestHandler, HTTPServer

@@ -23,2 +24,16 @@ TCPServer.allow_reuse_address = True

class OverpyBaseRequestHandler(BaseRequestHandler):
def handle(self):
for data in self.get_response(self):
self.request.send(data)
@staticmethod
def get_response(self):
yield b""
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
pass
def read_file(filename, mode="r"):

@@ -29,9 +44,2 @@ filename = os.path.join(os.path.dirname(__file__), filename)

def server_thread(server):
request = server.get_request()
server.process_request(*request)
server.server_close()
server.socket.close()
def new_server_thread(handle_cls, port=None):

@@ -45,14 +53,17 @@ global current_port

server = TCPServer(
server = ThreadedHTTPServer(
(HOST, port),
handle_cls
)
p = Process(target=server_thread, args=(server,))
p.start()
# Give the server some time to bind
# Is there a better option?
time.sleep(0.2)
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
return (
"http://%s:%d" % (HOST, port),
p
server
)
def stop_server_thread(server):
server.shutdown()
server.server_close()

@@ -42,2 +42,24 @@ import overpy

assert e.code == 123
assert str(e).endswith("123")
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"

@@ -101,2 +101,19 @@ import pytest

}
)
)
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"))
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"))

@@ -5,90 +5,129 @@ import pytest

from tests import BaseRequestHandler
from tests import read_file, new_server_thread
from tests import BaseHTTPRequestHandler
from tests import read_file, new_server_thread, stop_server_thread
class HandleOverpassBadRequest(BaseRequestHandler):
def handle_bad_request(request):
request.send_response(400, "Bad Request")
request.send_header("Content-Type", "text/html; charset=utf-8")
request.end_headers()
request.wfile.write(read_file("response/bad-request.html", "rb"))
def handle_bad_request_encoding(request):
request.send_response(400, "Bad Request")
request.send_header("Content-Type", "text/html; charset=utf-8")
request.end_headers()
request.wfile.write(read_file("response/bad-request-encoding.html", "rb"))
def handle_too_many_requests(request):
request.send_response(429, "Too Many Requests")
request.send_header("Content-Type", "text/html; charset=utf-8")
request.end_headers()
request.wfile.write(b"Too Many Requests")
def handle_gateway_timeout(request):
request.send_response(504, "Gateway Timeout")
request.send_header("Content-Type", "text/html; charset=utf-8")
request.end_headers()
request.wfile.write(b"Gateway Timeout")
def handle_unknown_content_type(request):
request.send_response(200, "OK")
request.send_header("Content-Type", "application/foobar")
request.end_headers()
request.wfile.write(read_file("xml/way-02.xml", "rb"))
def handle_unknown_http_status_code(request):
request.send_response(123, "Unknown")
request.send_header("Content-Type", "text/html; charset=utf-8")
request.end_headers()
request.wfile.write(b"Unknown status code")
class HandleOverpassBadRequest(BaseHTTPRequestHandler):
"""
Simulate the response if the query string has syntax errors
"""
def handle(self):
self.request.send(b"HTTP/1.0 400 Bad Request\r\n")
self.request.send(b"Content-Type text/html; charset=utf-8\r\n")
self.request.send(b"\r\n")
self.request.send(read_file("response/bad-request.html", "rb"))
def do_POST(self):
handle_bad_request(self)
class HandleOverpassBadRequestEncoding(BaseRequestHandler):
class HandleOverpassBadRequestEncoding(BaseHTTPRequestHandler):
"""
"""
def handle(self):
self.request.send(b"HTTP/1.0 400 Bad Request\r\n")
self.request.send(b"Content-Type text/html; charset=utf-8\r\n")
self.request.send(b"\r\n")
self.request.send(read_file("response/bad-request-encoding.html", "rb"))
def do_POST(self):
handle_bad_request_encoding(self)
class HandleOverpassTooManyRequests(BaseRequestHandler):
class HandleOverpassTooManyRequests(BaseHTTPRequestHandler):
"""
"""
def handle(self):
self.request.send(b"HTTP/1.0 429 Too Many Requests\r\n")
self.request.send(b"Content-Type text/html; charset=utf-8\r\n")
self.request.send(b"\r\n")
self.request.send(b"Too Many Requests")
def do_POST(self):
handle_too_many_requests(self)
class HandleOverpassGatewayTimeout(BaseRequestHandler):
class HandleOverpassGatewayTimeout(BaseHTTPRequestHandler):
"""
"""
def handle(self):
self.request.send(b"HTTP/1.0 504 Gateway Timeout\r\n")
self.request.send(b"Content-Type text/html; charset=utf-8\r\n")
self.request.send(b"\r\n")
self.request.send(b"Gateway Timeout")
def do_POST(self):
handle_gateway_timeout(self)
class HandleOverpassUnknownHTTPStatusCode(BaseRequestHandler):
class HandleOverpassUnknownHTTPStatusCode(BaseHTTPRequestHandler):
"""
"""
def handle(self):
self.request.send(b"HTTP/1.0 123 Unknown\r\n")
self.request.send(b"Content-Type text/html; charset=utf-8\r\n")
self.request.send(b"\r\n")
self.request.send(b"Unknown status code")
def do_POST(self):
handle_unknown_http_status_code(self)
class HandleResponseJSON(BaseRequestHandler):
class HandleResponseJSON(BaseHTTPRequestHandler):
"""
"""
def handle(self):
self.request.send(b"HTTP/1.0 200 OK\r\n")
self.request.send(b"Content-Type: application/json\r\n")
self.request.send(b"\r\n")
self.request.send(read_file("json/way-02.json", "rb"))
def do_POST(self):
self.send_response(200, "OK")
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(read_file("json/way-02.json", "rb"))
class HandleResponseXML(BaseRequestHandler):
class HandleResponseXML(BaseHTTPRequestHandler):
"""
"""
def handle(self):
self.request.send(b"HTTP/1.0 200 OK\r\n")
self.request.send(b"Content-Type: application/osm3s+xml\r\n")
self.request.send(b"\r\n")
self.request.send(read_file("xml/way-02.xml", "rb"))
def do_POST(self):
self.send_response(200, "OK")
self.send_header("Content-Type", "application/osm3s+xml")
self.end_headers()
self.wfile.write(read_file("xml/way-02.xml", "rb"))
class HandleResponseUnknown(BaseRequestHandler):
class HandleResponseUnknown(BaseHTTPRequestHandler):
"""
"""
def handle(self):
self.request.send(b"HTTP/1.0 200 OK\r\n")
self.request.send(b"Content-Type: application/foobar\r\n")
self.request.send(b"\r\n")
self.request.send(read_file("xml/way-02.xml", "rb"))
def do_POST(self):
handle_unknown_content_type(self)
class HandleRetry(BaseHTTPRequestHandler):
default_handler_func = [
handle_bad_request,
handle_bad_request_encoding,
handle_too_many_requests,
handle_gateway_timeout,
handle_unknown_content_type,
handle_unknown_http_status_code
]
def do_POST(self):
f = self.default_handler_func.pop(0)
f(self)
class TestQuery(object):
def test_chunk_size(self):
url, t = new_server_thread(HandleResponseJSON)
url, server = new_server_thread(HandleResponseJSON)

@@ -98,7 +137,7 @@ api = overpy.Overpass(read_chunk_size=128)

result = api.query("[out:json];node(50.745,7.17,50.75,7.18);out;")
t.join()
stop_server_thread(server)
assert len(result.nodes) > 0
def test_overpass_syntax_error(self):
url, t = new_server_thread(HandleOverpassBadRequest)
url, server = new_server_thread(HandleOverpassBadRequest)

@@ -113,3 +152,3 @@ api = overpy.Overpass()

))
t.join()
stop_server_thread(server)

@@ -122,3 +161,3 @@ def test_overpass_syntax_error_encoding_error(self):

url, t = new_server_thread(HandleOverpassBadRequestEncoding)
url, server = new_server_thread(HandleOverpassBadRequestEncoding)

@@ -133,6 +172,6 @@ api = overpy.Overpass()

))
t.join()
stop_server_thread(server)
def test_overpass_too_many_requests(self):
url, t = new_server_thread(HandleOverpassTooManyRequests)
url, server = new_server_thread(HandleOverpassTooManyRequests)

@@ -146,6 +185,6 @@ api = overpy.Overpass()

))
t.join()
stop_server_thread(server)
def test_overpass_gateway_timeout(self):
url, t = new_server_thread(HandleOverpassGatewayTimeout)
url, server = new_server_thread(HandleOverpassGatewayTimeout)

@@ -159,6 +198,6 @@ api = overpy.Overpass()

))
t.join()
stop_server_thread(server)
def test_overpass_unknown_status_code(self):
url, t = new_server_thread(HandleOverpassUnknownHTTPStatusCode)
url, server = new_server_thread(HandleOverpassUnknownHTTPStatusCode)

@@ -172,6 +211,6 @@ api = overpy.Overpass()

))
t.join()
stop_server_thread(server)
def test_response_json(self):
url, t = new_server_thread(HandleResponseJSON)
url, server = new_server_thread(HandleResponseJSON)

@@ -181,7 +220,7 @@ api = overpy.Overpass()

result = api.query("[out:json];node(50.745,7.17,50.75,7.18);out;")
t.join()
stop_server_thread(server)
assert len(result.nodes) > 0
def test_response_unknown(self):
url, t = new_server_thread(HandleResponseUnknown)
url, server = new_server_thread(HandleResponseUnknown)

@@ -192,6 +231,6 @@ api = overpy.Overpass()

api.query("[out:xml];node(50.745,7.17,50.75,7.18);out;")
t.join()
stop_server_thread(server)
def test_response_xml(self):
url, t = new_server_thread(HandleResponseXML)
url, server = new_server_thread(HandleResponseXML)

@@ -201,3 +240,17 @@ api = overpy.Overpass()

result = api.query("[out:xml];node(50.745,7.17,50.75,7.18);out;")
t.join()
assert len(result.nodes) > 0
stop_server_thread(server)
assert len(result.nodes) > 0
def test_retry(self):
url, server = new_server_thread(HandleRetry)
api = overpy.Overpass()
# HandleRetry.default_handler_cls should contain at least 2 classes to process
api.max_retry_count = len(HandleRetry.default_handler_func) - 1
api.url = url
with pytest.raises(overpy.exception.MaxRetriesReached):
api.query((
"way(1);"
"out body;"
))
stop_server_thread(server)

@@ -5,33 +5,34 @@ import pytest

from tests import read_file, new_server_thread, BaseRequestHandler
from tests import BaseHTTPRequestHandler
from tests import read_file, new_server_thread, stop_server_thread
class HandleResponseJSON01(BaseRequestHandler):
class HandleResponseJSON01(BaseHTTPRequestHandler):
"""
"""
def handle(self):
self.request.send(b"HTTP/1.0 200 OK\r\n")
self.request.send(b"Content-Type: application/json\r\n")
self.request.send(b"\r\n")
self.request.send(read_file("json/result-way-01.json", "rb"))
def do_POST(self):
self.send_response(200, "OK")
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(read_file("json/result-way-01.json", "rb"))
class HandleResponseJSON02(BaseRequestHandler):
class HandleResponseJSON02(BaseHTTPRequestHandler):
"""
"""
def handle(self):
self.request.send(b"HTTP/1.0 200 OK\r\n")
self.request.send(b"Content-Type: application/json\r\n")
self.request.send(b"\r\n")
self.request.send(read_file("json/result-way-02.json", "rb"))
def do_POST(self):
self.send_response(200, "OK")
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(read_file("json/result-way-02.json", "rb"))
class HandleResponseJSON03(BaseRequestHandler):
class HandleResponseJSON03(BaseHTTPRequestHandler):
"""
"""
def handle(self):
self.request.send(b"HTTP/1.0 200 OK\r\n")
self.request.send(b"Content-Type: application/json\r\n")
self.request.send(b"\r\n")
self.request.send(read_file("json/result-way-03.json", "rb"))
def do_POST(self):
self.send_response(200, "OK")
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(read_file("json/result-way-03.json", "rb"))

@@ -41,3 +42,3 @@

def test_missing_unresolvable(self):
url, t = new_server_thread(HandleResponseJSON01)
url, server = new_server_thread(HandleResponseJSON01)

@@ -61,6 +62,6 @@ api = overpy.Overpass()

assert len(result.nodes) == 0
t.join()
stop_server_thread(server)
def test_missing_partly_unresolvable(self):
url, t = new_server_thread(HandleResponseJSON02)
url, server = new_server_thread(HandleResponseJSON02)

@@ -84,6 +85,6 @@ api = overpy.Overpass()

assert len(result.nodes) == 1
t.join()
stop_server_thread(server)
def test_missing_resolvable(self):
url, t = new_server_thread(HandleResponseJSON03)
url, server = new_server_thread(HandleResponseJSON03)

@@ -107,2 +108,2 @@ api = overpy.Overpass()

t.join()
stop_server_thread(server)

@@ -5,13 +5,14 @@ import pytest

from tests import read_file, new_server_thread, BaseRequestHandler
from tests.base_class import BaseTestWay
from tests import read_file, new_server_thread, stop_server_thread, BaseHTTPRequestHandler
class HandleResponseJSON02(BaseRequestHandler):
class HandleResponseJSON02(BaseHTTPRequestHandler):
"""
"""
def handle(self):
self.request.send(b"HTTP/1.0 200 OK\r\n")
self.request.send(b"Content-Type: application/json\r\n")
self.request.send(b"\r\n")
self.request.send(read_file("json/result-expand-02.json", "rb"))
def do_POST(self):
self.send_response(200, "OK")
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(read_file("json/result-expand-02.json", "rb"))

@@ -51,3 +52,3 @@

def test_missing_unresolvable(self):
url, t = new_server_thread(HandleResponseJSON02)
url, server = new_server_thread(HandleResponseJSON02)

@@ -60,6 +61,6 @@ api = overpy.Overpass()

result1.get_area(123, resolve_missing=True)
t.join()
stop_server_thread(server)
def test_missing_resolvable(self):
url, t = new_server_thread(HandleResponseJSON02)
url, server = new_server_thread(HandleResponseJSON02)

@@ -80,3 +81,3 @@ api = overpy.Overpass()

t.join()
stop_server_thread(server)

@@ -86,3 +87,3 @@

def test_missing_unresolvable(self):
url, t = new_server_thread(HandleResponseJSON02)
url, server = new_server_thread(HandleResponseJSON02)

@@ -95,6 +96,6 @@ api = overpy.Overpass()

result1.get_node(123, resolve_missing=True)
t.join()
stop_server_thread(server)
def test_missing_resolvable(self):
url, t = new_server_thread(HandleResponseJSON02)
url, server = new_server_thread(HandleResponseJSON02)

@@ -115,8 +116,25 @@ api = overpy.Overpass()

t.join()
stop_server_thread(server)
class TestPickle(BaseTestWay):
def test_way02(self):
"""
Try to pickle and unpickle the result object
"""
import pickle
api = overpy.Overpass()
result = api.parse_json(read_file("json/way-02.json"))
self._test_way02(result)
# do pickle and unpickle
result_string = pickle.dumps(result)
new_result = pickle.loads(result_string)
# test new result
self._test_way02(new_result)
class TestRelation(object):
def test_missing_unresolvable(self):
url, t = new_server_thread(HandleResponseJSON02)
url, server = new_server_thread(HandleResponseJSON02)

@@ -129,6 +147,6 @@ api = overpy.Overpass()

result1.get_relation(123, resolve_missing=True)
t.join()
stop_server_thread(server)
def test_missing_resolvable(self):
url, t = new_server_thread(HandleResponseJSON02)
url, server = new_server_thread(HandleResponseJSON02)

@@ -149,3 +167,3 @@ api = overpy.Overpass()

t.join()
stop_server_thread(server)

@@ -155,3 +173,3 @@

def test_missing_unresolvable(self):
url, t = new_server_thread(HandleResponseJSON02)
url, server = new_server_thread(HandleResponseJSON02)

@@ -164,6 +182,6 @@ api = overpy.Overpass()

result1.get_way(123, resolve_missing=True)
t.join()
stop_server_thread(server)
def test_missing_resolvable(self):
url, t = new_server_thread(HandleResponseJSON02)
url, server = new_server_thread(HandleResponseJSON02)

@@ -184,2 +202,2 @@ api = overpy.Overpass()

t.join()
stop_server_thread(server)

@@ -172,1 +172,40 @@ import pytest

overpy.Way.from_xml(node)
class TestParser(BaseTestNodes):
def test_exception(self):
with pytest.raises(overpy.exception.OverPyException):
overpy.Result.from_xml(123)
def test_xml_element(self):
import xml.etree.ElementTree as ET
data = read_file("xml/node-01.xml")
root = ET.fromstring(data)
result = overpy.Result.from_xml(root)
assert isinstance(result, overpy.Result)
self._test_node01(result)
def test_xml_autodetect_parser(self):
data = read_file("xml/node-01.xml")
result = overpy.Result.from_xml(data)
assert isinstance(result, overpy.Result)
self._test_node01(result)
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"))
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"))