Skip to content

Commit 71bcf2e

Browse files
authored
Merge pull request #215 from lonvia/fix-socket-timeouts-again
Simplify handling of custom request parameters
2 parents 055254c + 201e454 commit 71bcf2e

File tree

4 files changed

+38
-57
lines changed

4 files changed

+38
-57
lines changed

src/osmium/replication/server.py

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,19 @@ class ReplicationServer:
3232
Replication change files allow to keep local OSM data up-to-date without
3333
downloading the full dataset again.
3434
35+
`url` contains the base URL of the replication service. This is the
36+
directory that contains the state file with the current state. If the
37+
replication service serves something other than osc.gz files, set
38+
the `diff_type` to the given file suffix.
39+
3540
ReplicationServer may be used as a context manager. In this case, it
3641
internally keeps a connection to the server making downloads faster.
3742
"""
3843

3944
def __init__(self, url: str, diff_type: str = 'osc.gz') -> None:
4045
self.baseurl = url
4146
self.diff_type = diff_type
47+
self.extra_request_params: Mapping[str, Any] = dict(timeout=60, stream=True)
4248
self.session: Optional[requests.Session] = None
4349

4450
def close(self) -> None:
@@ -55,39 +61,37 @@ def __enter__(self) -> 'ReplicationServer':
5561
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
5662
self.close()
5763

64+
def set_request_parameter(self, key: str, value: Any) -> None:
65+
""" Set a parameter which will be handed to the requests library
66+
when calling `requests.get()`. This
67+
may be used to set custom headers, timeouts and similar parameters.
68+
See the `requests documentation <https://requests.readthedocs.io/en/latest/api/?highlight=get#requests.request>`_
69+
for possible parameters. Per default, a timeout of 60 sec is set
70+
and streaming download enabled.
71+
"""
72+
self.extra_request_params[key] = value
73+
5874
def make_request(self, url: str) -> urlrequest.Request:
5975
headers = {"User-Agent" : f"pyosmium/{version.pyosmium_release}"}
6076
return urlrequest.Request(url, headers=headers)
6177

6278
def open_url(self, url: urlrequest.Request) -> Any:
6379
""" Download a resource from the given URL and return a byte sequence
6480
of the content.
65-
66-
This method has no support for cookies or any special authentication
67-
methods. If you need these, you have to provide your own custom URL
68-
opener. Overwrite open_url() with a method that receives an
69-
urlrequest.Request object and returns a ByteIO-like object or a
70-
requests.Response.
71-
72-
Example::
73-
74-
opener = urlrequest.build_opener()
75-
opener.addheaders = [('X-Fancy-Header', 'important_content')]
76-
77-
svr = ReplicationServer()
78-
svr.open_url = opener.open
7981
"""
80-
headers = dict()
81-
for h in url.header_items():
82-
headers[h[0]] = h[1]
82+
if 'headers' in self.extra_request_params:
83+
get_params = self.extra_request_params
84+
else:
85+
get_params = dict(self.extra_request_params)
86+
get_params['headers'] = {k: v for k,v in url.header_items()}
8387

8488
if self.session is not None:
85-
return self.session.get(url.get_full_url(), headers=headers, stream=True)
89+
return self.session.get(url.get_full_url(), **get_params)
8690

8791
@contextmanager
8892
def _get_url_with_session() -> Iterator[requests.Response]:
8993
with requests.Session() as session:
90-
request = session.get(url.get_full_url(), headers=headers, stream=True)
94+
request = session.get(url.get_full_url(), **get_params)
9195
yield request
9296

9397
return _get_url_with_session()

test/test_pyosmium_get_changes.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,6 @@ def mock_get(session, url, **kwargs):
4848
monkeypatch.setattr(osmium.replication.server.requests.Session, "get", mock_get)
4949

5050

51-
@pytest.fixture
52-
def mock_urllib(self, monkeypatch):
53-
def mock_get(_, url, **kwargs):
54-
return BytesIO(self.urls[url.get_full_url()])
55-
monkeypatch.setattr(self.script['urlrequest'].OpenerDirector, "open", mock_get)
56-
57-
5851
def url(self, url, result):
5952
self.urls[url] = dedent(result).encode()
6053

@@ -103,7 +96,7 @@ def test_init_from_seq_file(self, tmp_path):
10396
assert fname.read_text() == '453'
10497

10598

106-
def test_init_date_with_cookie(self, capsys, tmp_path, mock_urllib):
99+
def test_init_date_with_cookie(self, capsys, tmp_path, mock_requests):
107100
self.url('https://planet.osm.org/replication/minute//state.txt',
108101
"""\
109102
sequenceNumber=100

tools/pyosmium-get-changes

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,14 @@ cookies to the server and will save received cookies to the jar file.
2727

2828
from argparse import ArgumentParser, RawDescriptionHelpFormatter, ArgumentTypeError
2929
import datetime as dt
30-
import socket
30+
import http.cookiejar
31+
3132
from osmium.replication import server as rserv
3233
from osmium.replication import newest_change_from_file
3334
from osmium.replication.utils import get_replication_header
3435
from osmium.version import pyosmium_release
3536
from osmium import SimpleHandler, WriteHandler
3637

37-
try:
38-
import http.cookiejar as cookiejarlib
39-
except ImportError:
40-
import cookielib as cookiejarlib
41-
import urllib.request as urlrequest
4238

4339
import re
4440
import sys
@@ -211,15 +207,13 @@ def main(args):
211207
or 'https://planet.osm.org/replication/minute/'
212208
logging.info("Using replication server at %s" % url)
213209

214-
socket.setdefaulttimeout(options.socket_timeout)
215-
216210
with rserv.ReplicationServer(url) as svr:
211+
svr.set_request_parameter('timeout', options.socket_timeout or None)
212+
217213
if options.cookie is not None:
218-
# According to the documentation, the cookie jar loads the file only if FileCookieJar.load is called.
219-
cookie_jar = cookiejarlib.MozillaCookieJar(options.cookie)
214+
cookie_jar = http.cookiejar.MozillaCookieJar(options.cookie)
220215
cookie_jar.load(options.cookie)
221-
opener = urlrequest.build_opener(urlrequest.HTTPCookieProcessor(cookie_jar))
222-
svr.open_url = opener.open
216+
svr.set_request_parameter('cookies', cookie_jar)
223217

224218
startseq = options.start.get_sequence(svr)
225219
if startseq is None:
@@ -245,6 +239,7 @@ def main(args):
245239
cookie_jar.save(options.cookie)
246240

247241
if endseq is None:
242+
log.error("Error while downloading diffs.")
248243
return 3
249244

250245
if options.outfile != '-' or options.seq_file is not None:

tools/pyosmium-up-to-date

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import re
3535
import sys
3636
import traceback
3737
import logging
38-
import socket
38+
import http.cookiejar
3939

4040
from argparse import ArgumentParser, RawDescriptionHelpFormatter
4141
import datetime as dt
@@ -47,15 +47,6 @@ from textwrap import dedent as msgfmt
4747
from tempfile import mktemp
4848
import os.path
4949

50-
try:
51-
import http.cookiejar as cookiejarlib
52-
except ImportError:
53-
import cookielib as cookiejarlib
54-
try:
55-
import urllib.request as urlrequest
56-
except ImportError:
57-
import urllib2 as urlrequest
58-
5950
log = logging.getLogger()
6051

6152
def update_from_osm_server(ts, options):
@@ -71,14 +62,14 @@ def update_from_osm_server(ts, options):
7162
def update_from_custom_server(url, seq, ts, options):
7263
"""Update from a custom URL, simply using the diff sequence as is."""
7364
with rserv.ReplicationServer(url, "osc.gz") as svr:
65+
log.info("Using replication service at %s", url)
66+
67+
svr.set_request_parameter('timeout', options.socket_timeout or None)
68+
7469
if options.cookie is not None:
75-
# According to the documentation, the cookie jar loads the file only if FileCookieJar.load is called.
76-
cookie_jar = cookiejarlib.MozillaCookieJar(options.cookie)
70+
cookie_jar = http.cookiejar.MozillaCookieJar(options.cookie)
7771
cookie_jar.load(options.cookie)
78-
opener = urlrequest.build_opener(urlrequest.HTTPCookieProcessor(cookie_jar))
79-
svr.open_url = opener.open
80-
81-
log.info("Using replication service at %s", url)
72+
svr.set_request_parameter('cookies', cookie_jar)
8273

8374
current = svr.get_state_info()
8475
if current is None:
@@ -244,8 +235,6 @@ if __name__ == '__main__':
244235
options = get_arg_parser(from_main=True).parse_args()
245236
log.setLevel(max(3 - options.loglevel, 0) * 10)
246237

247-
socket.setdefaulttimeout(options.socket_timeout)
248-
249238
try:
250239
url, seq, ts = compute_start_point(options)
251240
except RuntimeError as e:

0 commit comments

Comments
 (0)