Skip to content

Commit a930927

Browse files
committed
add typing information for replication functions
1 parent c557053 commit a930927

File tree

5 files changed

+59
-41
lines changed

5 files changed

+59
-41
lines changed

src/osmium/_osmium.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ class BaseHandler: ...
1616

1717
class SimpleHandler(BaseHandler):
1818
def __init__(self) -> None: ...
19-
def apply_buffer(self, buffer: ByteString, format: str, locations: bool = ..., idx: str = ...) -> None: ...
19+
def apply_buffer(self, buffer: Union[ByteString, str], format: str, locations: bool = ..., idx: str = ...) -> None: ...
2020
def apply_file(self, filename: StrPath, locations: bool = ..., idx: str = ...) -> None: ...
2121

2222
class MergeInputReader:
2323
def __init__(self) -> None: ...
24-
def add_buffer(self, buffer: ByteString, format: str) -> int: ...
24+
def add_buffer(self, buffer: Union[ByteString, str], format: str) -> int: ...
2525
def add_file(self, file: str) -> int: ...
2626
def apply(self, handler: BaseHandler, idx: str = ..., simplify: bool = ...) -> None: ...
2727
def apply_to_reader(self, reader: osmium.io.Reader, writer: osmium.io.Writer, with_history: bool = ...) -> None: ...

src/osmium/py.typed

Whitespace-only changes.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import datetime
2+
3+
def newest_change_from_file(filename: str) -> datetime.datetime: ...

src/osmium/replication/server.py

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
""" Helper functions to communicate with replication servers.
22
"""
3-
3+
from typing import NamedTuple, Optional, Any, Iterator, cast, Mapping, Tuple
44
import requests
55
import urllib.request as urlrequest
66
from urllib.error import URLError
@@ -9,7 +9,7 @@
99
from contextlib import contextmanager
1010
from math import ceil
1111

12-
from osmium import MergeInputReader
12+
from osmium import MergeInputReader, BaseHandler
1313
from osmium import io as oio
1414
from osmium import version
1515

@@ -18,8 +18,14 @@
1818
LOG = logging.getLogger('pyosmium')
1919
LOG.addHandler(logging.NullHandler())
2020

21-
OsmosisState = namedtuple('OsmosisState', ['sequence', 'timestamp'])
22-
DownloadResult = namedtuple('DownloadResult', ['id', 'reader', 'newest'])
21+
class OsmosisState(NamedTuple):
22+
sequence: int
23+
timestamp: dt.datetime
24+
25+
class DownloadResult(NamedTuple):
26+
id: int
27+
reader: MergeInputReader
28+
newest: int
2329

2430
class ReplicationServer:
2531
""" Represents a connection to a server that publishes replication data.
@@ -30,37 +36,37 @@ class ReplicationServer:
3036
internally keeps a connection to the server making downloads faster.
3137
"""
3238

33-
def __init__(self, url, diff_type='osc.gz'):
39+
def __init__(self, url: str, diff_type: str = 'osc.gz') -> None:
3440
self.baseurl = url
3541
self.diff_type = diff_type
36-
self.session = None
42+
self.session: Optional[requests.Session] = None
3743

38-
def close(self):
44+
def close(self) -> None:
3945
""" Close any open connection to the replication server.
4046
"""
4147
if self.session is not None:
4248
self.session.close()
4349
self.session = None
4450

45-
def __enter__(self):
51+
def __enter__(self) -> 'ReplicationServer':
4652
self.session = requests.Session()
4753
return self
4854

49-
def __exit__(self, exc_type, exc_value, traceback):
55+
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
5056
self.close()
5157

52-
def make_request(self, url):
58+
def make_request(self, url: str) -> urlrequest.Request:
5359
headers = {"User-Agent" : "pyosmium/{}".format(version.pyosmium_release)}
5460
return urlrequest.Request(url, headers=headers)
5561

56-
def open_url(self, url):
62+
def open_url(self, url: urlrequest.Request) -> Any:
5763
""" Download a resource from the given URL and return a byte sequence
5864
of the content.
5965
6066
This method has no support for cookies or any special authentication
6167
methods. If you need these, you have to provide your own custom URL
6268
opener. Overwrite open_url() with a method that receives an
63-
urllib.Request object and returns a ByteIO-like object or a
69+
urlrequest.Request object and returns a ByteIO-like object or a
6470
requests.Response.
6571
6672
Example::
@@ -79,14 +85,14 @@ def open_url(self, url):
7985
return self.session.get(url.get_full_url(), headers=headers, stream=True)
8086

8187
@contextmanager
82-
def _get_url_with_session():
88+
def _get_url_with_session() -> Iterator[requests.Response]:
8389
with requests.Session() as session:
8490
request = session.get(url.get_full_url(), headers=headers, stream=True)
8591
yield request
8692

8793
return _get_url_with_session()
8894

89-
def collect_diffs(self, start_id, max_size=1024):
95+
def collect_diffs(self, start_id: int, max_size: int = 1024) -> Optional[DownloadResult]:
9096
""" Create a MergeInputReader and download diffs starting with sequence
9197
id `start_id` into it. `max_size`
9298
restricts the number of diffs that are downloaded. The download
@@ -131,7 +137,9 @@ def collect_diffs(self, start_id, max_size=1024):
131137

132138
return DownloadResult(current_id - 1, rd, newest.sequence)
133139

134-
def apply_diffs(self, handler, start_id, max_size=1024, idx="", simplify=True):
140+
def apply_diffs(self, handler: BaseHandler, start_id: int,
141+
max_size: int = 1024, idx: str = "",
142+
simplify: bool = True) -> Optional[int]:
135143
""" Download diffs starting with sequence id `start_id`, merge them
136144
together and then apply them to handler `handler`. `max_size`
137145
restricts the number of diffs that are downloaded. The download
@@ -165,9 +173,11 @@ def apply_diffs(self, handler, start_id, max_size=1024, idx="", simplify=True):
165173

166174
return diffs.id
167175

168-
def apply_diffs_to_file(self, infile, outfile, start_id, max_size=1024,
169-
set_replication_header=True, extra_headers=None,
170-
outformat=None):
176+
def apply_diffs_to_file(self, infile: str, outfile: str,
177+
start_id: int, max_size: int = 1024,
178+
set_replication_header: bool = True,
179+
extra_headers: Optional[Mapping[str, str]] = None,
180+
outformat: Optional[str] = None) -> Optional[Tuple[int, int]]:
171181
""" Download diffs starting with sequence id `start_id`, merge them
172182
with the data from the OSM file named `infile` and write the result
173183
into a file with the name `outfile`. The output file must not yet
@@ -230,7 +240,8 @@ def apply_diffs_to_file(self, infile, outfile, start_id, max_size=1024,
230240
return (diffs.id, diffs.newest)
231241

232242

233-
def timestamp_to_sequence(self, timestamp, balanced_search=False):
243+
def timestamp_to_sequence(self, timestamp: dt.datetime,
244+
balanced_search: bool = False) -> Optional[int]:
234245
""" Get the sequence number of the replication file that contains the
235246
given timestamp. The search algorithm is optimised for replication
236247
servers that publish updates in regular intervals. For servers
@@ -312,7 +323,7 @@ def timestamp_to_sequence(self, timestamp, balanced_search=False):
312323
return lower.sequence
313324

314325

315-
def get_state_info(self, seq=None, retries=2):
326+
def get_state_info(self, seq: Optional[int] = None, retries: int = 2) -> Optional[OsmosisState]:
316327
""" Downloads and returns the state information for the given
317328
sequence. If the download is successful, a namedtuple with
318329
`sequence` and `timestamp` is returned, otherwise the function
@@ -359,21 +370,21 @@ def get_state_info(self, seq=None, retries=2):
359370

360371
return None
361372

362-
def get_diff_block(self, seq):
373+
def get_diff_block(self, seq: int) -> str:
363374
""" Downloads the diff with the given sequence number and returns
364375
it as a byte sequence. Throws a :code:`urllib.error.HTTPError`
365376
if the file cannot be downloaded.
366377
"""
367378
with self.open_url(self.make_request(self.get_diff_url(seq))) as resp:
368379
if hasattr(resp, 'content'):
369380
# generated by requests
370-
return resp.content
381+
return cast(str, resp.content)
371382

372383
# generated by urllib.request
373-
return resp.read()
384+
return cast(str, resp.read())
374385

375386

376-
def get_state_url(self, seq):
387+
def get_state_url(self, seq: Optional[int]) -> str:
377388
""" Returns the URL of the state.txt files for a given sequence id.
378389
379390
If seq is `None` the URL for the latest state info is returned,
@@ -387,7 +398,7 @@ def get_state_url(self, seq):
387398
(self.baseurl, seq / 1000000, (seq % 1000000) / 1000, seq % 1000)
388399

389400

390-
def get_diff_url(self, seq):
401+
def get_diff_url(self, seq: int) -> str:
391402
""" Returns the URL to the diff file for the given sequence id.
392403
"""
393404
return '%s/%03i/%03i/%03i.%s' % \

src/osmium/replication/utils.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
""" Helper functions for change file handling. """
2-
2+
from typing import NamedTuple, Optional
33
import logging
44
import datetime as dt
55
from collections import namedtuple
@@ -8,10 +8,13 @@
88

99
LOG = logging.getLogger('pyosmium')
1010

11-
ReplicationHeader = namedtuple('ReplicationHeader',
12-
['url', 'sequence', 'timestamp'])
11+
class ReplicationHeader(NamedTuple):
12+
url: Optional[str]
13+
sequence: Optional[int]
14+
timestamp: Optional[dt.datetime]
15+
1316

14-
def get_replication_header(fname):
17+
def get_replication_header(fname: str) -> ReplicationHeader:
1518
""" Scans the given file for an Osmosis replication header. It returns
1619
a namedtuple with `url`, `sequence` and `timestamp`. Each or all fields
1720
may be None, if the piece of information is not avilable. If any of
@@ -24,20 +27,21 @@ def get_replication_header(fname):
2427
r = oreader(fname, NOTHING)
2528
h = r.header()
2629

27-
ts = h.get("osmosis_replication_timestamp")
28-
url = h.get("osmosis_replication_base_url")
30+
tsstr = h.get("osmosis_replication_timestamp")
31+
url: Optional[str] = h.get("osmosis_replication_base_url")
2932

30-
if url or ts:
33+
if url or tsstr:
3134
LOG.debug("Replication information found in OSM file header.")
3235

3336
if url:
3437
LOG.debug("Replication URL: %s", url)
3538
# the sequence ID is only considered valid, if an URL is given
36-
seq = h.get("osmosis_replication_sequence_number")
37-
if seq:
38-
LOG.debug("Replication sequence: %s", seq)
39+
seqstr = h.get("osmosis_replication_sequence_number")
40+
seq: Optional[int]
41+
if seqstr:
42+
LOG.debug("Replication sequence: %s", seqstr)
3943
try:
40-
seq = int(seq)
44+
seq = int(seqstr)
4145
if seq < 0:
4246
LOG.warning("Sequence id '%d' in OSM file header is negative. Ignored.", seq)
4347
seq = None
@@ -50,10 +54,10 @@ def get_replication_header(fname):
5054
url = None
5155
seq = None
5256

53-
if ts:
54-
LOG.debug("Replication timestamp: %s", ts)
57+
if tsstr:
58+
LOG.debug("Replication timestamp: %s", tsstr)
5559
try:
56-
ts = dt.datetime.strptime(ts, "%Y-%m-%dT%H:%M:%SZ")
60+
ts = dt.datetime.strptime(tsstr, "%Y-%m-%dT%H:%M:%SZ")
5761
ts = ts.replace(tzinfo=dt.timezone.utc)
5862

5963
except ValueError:

0 commit comments

Comments
 (0)