From 497855864df7566339786000970b811bb0a3e29b Mon Sep 17 00:00:00 2001 From: Wiktor Niesiobedzki Date: Sun, 6 May 2018 01:07:34 +0200 Subject: [PATCH 01/16] Typing information for pyosmium --- setup.py | 36 ++++- src/osmium/_osmium.pyi | 75 +++++++++ src/osmium/geom.pyi | 47 ++++++ src/osmium/index.pyi | 19 +++ src/osmium/io.pyi | 39 +++++ src/osmium/osm/__init__.pyi | 13 ++ src/osmium/osm/_osm.pyi | 207 ++++++++++++++++++++++++ src/osmium/osm/mutable.pyi | 53 ++++++ src/osmium/replication/_replication.pyi | 4 + src/osmium/replication/server.pyi | 38 +++++ src/osmium/replication/utils.pyi | 15 ++ 11 files changed, 545 insertions(+), 1 deletion(-) create mode 100644 src/osmium/_osmium.pyi create mode 100644 src/osmium/geom.pyi create mode 100644 src/osmium/index.pyi create mode 100644 src/osmium/io.pyi create mode 100644 src/osmium/osm/__init__.pyi create mode 100644 src/osmium/osm/_osm.pyi create mode 100644 src/osmium/osm/mutable.pyi create mode 100644 src/osmium/replication/_replication.pyi create mode 100644 src/osmium/replication/server.pyi create mode 100644 src/osmium/replication/utils.pyi diff --git a/setup.py b/setup.py index 0822c47c..30a81f0c 100644 --- a/setup.py +++ b/setup.py @@ -6,6 +6,7 @@ from ctypes.util import find_library import os import os.path as osp +import sys includes = [] libs = [] @@ -206,6 +207,15 @@ def cpp_compiler(compiler): descfile=open('README.rst') long_description = descfile.read() descfile.close() +base_data_files_folder = os.path.join("lib", "python{}.{}".format(*sys.version_info[:2]), "site-packages", "osmium") + + +def path_join_list(path_prefix, lst): + ret = [] + for p in lst: + ret.append(os.path.join(path_prefix, p)) + return ret + setup (name = 'osmium', version = pyosmium_release, @@ -225,5 +235,29 @@ def cpp_compiler(compiler): package_dir = {'' : 'src'}, package_data = { 'osmium' : [ '*.dll' ] }, cmdclass={'sdist' : My_sdist}, - ext_modules = extensions) + ext_modules = extensions, + data_files = [ + ( + base_data_files_folder, + path_join_list( + os.path.join("src", "osmium"), + ["index.pyi", "io.pyi", "geom.pyi", "_osmium.pyi"] + ) + ), + ( + os.path.join(base_data_files_folder, "replication"), + path_join_list( + os.path.join("src", "osmium", "replication"), + ["server.pyi", "_replication.pyi", "utils.pyi"] + ) + ), + ( + os.path.join(base_data_files_folder, "osm"), + path_join_list( + os.path.join("src", "osmium", "osm"), + ["mutable.pyi", "__init__.pyi", "_osm.pyi"] + ) + ) + ], + ) diff --git a/src/osmium/_osmium.pyi b/src/osmium/_osmium.pyi new file mode 100644 index 00000000..9ccb9c19 --- /dev/null +++ b/src/osmium/_osmium.pyi @@ -0,0 +1,75 @@ +import typing + +from .io import Reader, Writer +from .osm import Location, Node, Way, Relation, Area, Changeset, mutable + + +class InvalidLocationError(RuntimeError): ... + + +class NotFoundError(KeyError): ... + + +class MergeInputReader(Reader): + def add_buffer(self, buffer, format: str) -> int: ... + + def add_file(self, file: str) -> int: ... + + def apply(self, handler: BaseHandler, idx: typing.Optional[str], simplify: bool = ...): ... + + def apply_to_reader(self, reader: Reader, writer: Writer, with_history: bool = ...): ... + + +LocationTable = typing.Mapping[int, Location] + + +class NodeLocationsForWays(LocationTable): + def ignore_errors(self): ... + + +class BaseHandler: + def node(self, node: Node): ... + + def way(self, way: Way): ... + + def relation(self, relation: Relation): ... + + def area(self, area: Area): ... + + def changeset(self, changeset: Changeset): ... + + def apply_start(self): ... + + +class SimpleHandler(BaseHandler): + def apply_buffer(self, buffer: bytes, format: str, locations: bool = ..., idx: str = ...): ... + + def apply_file(self, filename: str, locations: bool = ..., idx: str = ...): ... + + +class SimpleWriter: + def __init__(self, arg2: str, arg3: typing.Optional[int]): ... # filename, buffer_size + + def add_node(self, node: typing.Union[Node, mutable.Node]): ... + + def add_relation(self, relation: typing.Union[Relation, mutable.Relation]): ... + + def add_way(self, way: typing.Union[Way, mutable.Way]): ... + + def close(self): ... + + +class WriteHandler(BaseHandler): + def __init__(self, arg2: str, arg3: typing.Optional[int]): ... # filename, buffer_size + + +@typing.overload +def apply(arg1: Reader, arg2: BaseHandler): ... # reader, write_handler + + +@typing.overload +def apply(arg1: Reader, arg2: NodeLocationsForWays): ... # reader, nodes_idx + + +@typing.overload +def apply(arg1: Reader, arg2: NodeLocationsForWays, arg3: BaseHandler): ... # reader, nodes_idx, write_handler diff --git a/src/osmium/geom.pyi b/src/osmium/geom.pyi new file mode 100644 index 00000000..b1767bb0 --- /dev/null +++ b/src/osmium/geom.pyi @@ -0,0 +1,47 @@ +import typing + +from .osm import WayNodeList, Area, Location, Node, NodeRef + + +class BaseFactory: + epsg: int + proj_string: str + + def create_linestring(self, list: WayNodeList, use_nodes: use_nodes, direction: direction) -> str: ... + + def create_multipolygon(self, area: Area) -> str: ... + + @typing.overload + def create_point(self, location: Location) -> str: ... + + @typing.overload + def create_point(self, node: Node) -> str: ... + + @typing.overload + def create_point(self, ref: NodeRef) -> str: ... + + +class GeoJSONFactory(BaseFactory): ... + + +class WKBFactory(BaseFactory): ... + + +class WKTFactory(BaseFactory): ... + + +def haversine_distance(list: WayNodeList) -> float: ... + + +class direction: + BACKWARD: direction = ... + FORWARD: direction = ... + names: typing.Dict[str, direction] = ... + values: typing.Dict[int, direction] = ... + + +class use_nodes: + ALL: use_nodes = ... + UNIQUE: use_nodes = ... + names: typing.Dict[str, use_nodes] = ... + values: typing.Dict[int, use_nodes] = ... diff --git a/src/osmium/index.pyi b/src/osmium/index.pyi new file mode 100644 index 00000000..60dfd3e2 --- /dev/null +++ b/src/osmium/index.pyi @@ -0,0 +1,19 @@ +import typing + +from .osm import Location + + +class LocationTable: + def clear(self): ... + + def get(self, id: int) -> Location: ... + + def set(self, id: int, loc: Location): ... + + def used_memory(self) -> int: ... + + +def create_map(map_type: str) -> LocationTable: ... + + +def map_types() -> typing.List[str]: ... diff --git a/src/osmium/io.pyi b/src/osmium/io.pyi new file mode 100644 index 00000000..1cb46ada --- /dev/null +++ b/src/osmium/io.pyi @@ -0,0 +1,39 @@ +import typing + +from .osm import Box + +osm_entity_bits = typing.NewType(int) + + +class Header: + has_multiple_object_versions: bool + + def box(self) -> Box: ... + + def get(self, key: str, default: typing.Optional[str]) -> str: ... + + def set(self, key: str, value: str): ... + + +class Reader: + @typing.overload + def __init__(self, arg2: str): ... + + @typing.overload + def __init__(self, arg2: str, arg3: osm_entity_bits): ... + + def close(self): ... + + def eof(self) -> bool: ... + + def header(self) -> Header: ... + + +class Writer: + @typing.overload + def __init__(self, arg2: str): ... + + @typing.overload + def __init__(self, arg2: str, arg3: Header): ... + + def close(self): ... diff --git a/src/osmium/osm/__init__.pyi b/src/osmium/osm/__init__.pyi new file mode 100644 index 00000000..09461d8d --- /dev/null +++ b/src/osmium/osm/__init__.pyi @@ -0,0 +1,13 @@ +from typing import Any + +from . import mutable +from ._osm import * + + +def create_mutable_node(node: Node, **args: Any) -> mutable.Node: ... + + +def create_mutable_way(way: Way, **args: Any) -> mutable.Way: ... + + +def create_mutable_relation(rel: Relation, **args: Any) -> mutable.Relation: ... diff --git a/src/osmium/osm/_osm.pyi b/src/osmium/osm/_osm.pyi new file mode 100644 index 00000000..b418f11d --- /dev/null +++ b/src/osmium/osm/_osm.pyi @@ -0,0 +1,207 @@ +import datetime + +import typing + +from osmium.osm import mutable +from osmium.replication.utils import Timestamp + +OSMObjectIdType = typing.NewType('OSMObjectId', int) +UnsginedOSMObjectIdType = typing.NewType('UnsginedOSMObjectIdType', OSMObjectIdType) +UidType = typing.NewType('UserId', int) +VersionType = typing.NewType('VersionType', int) + + +class OSMObject: + id: OSMObjectIdType + deleted: bool + visible: bool + version: VersionType + changeset: ChangesetId + uid: UidType + timestamp: Timestamp + user: str + tags: TagList + + def positive_id(self) -> UnsginedOSMObjectIdType: ... + + def user_is_anonymous(self) -> bool: ... + + +class NodeRefList: + def __len__(self) -> int: ... + + def __getitem__(self, arg2: int) -> NodeRef: ... + + def __iter__(self) -> typing.Iterable[NodeRef]: ... + + def ends_have_same_id(self) -> bool: ... + + def ends_have_same_location(self) -> bool: ... + + def is_closed(self) -> bool: ... + + +class InnerRing(NodeRefList): ... + + +InnerRingIterator = typing.Iterable[InnerRing] + + +class OuterRing(NodeRefList): ... + + +OuterRingIterator = typing.Iterable[OuterRing] + + +class Area(OSMObject): + def from_way(self) -> bool: ... + + def orig_id(self) -> OSMObjectIdType: ... + + def is_multipolygon(self) -> bool: ... + + def num_rings(self) -> typing.Tuple[int, int]: ... + + def outer_rings(self) -> OuterRingIterator: ... + + def inner_rings(self) -> InnerRingIterator: ... + + +class Box: + bottom_left: Location + top_right: Location + + @typing.overload + def __init__(self): ... + + @typing.overload + def __init__(self, arg2: float, arg3: float, arg4: float, arg5: float): ... + + @typing.overload + def __init__(self, arg2: Location, arg3: Location): ... + + def contains(self, location: Location) -> bool: ... + + @typing.overload + def extend(self, arg2: Location) -> Box: ... + + @typing.overload + def extend(self, arg2: Box) -> Box: ... + + def size(self) -> float: ... + + def valid(self) -> bool: ... + + +ChangesetId = typing.NewType('ChangesetId', int) + + +class Changeset: + id: ChangesetId + uid: UidType + created_at: datetime.datetime # ??? + closed_at: datetime.datetime # ??? + open: bool + num_changes: int + bounds: Box + user: str + tags: TagList + + def user_is_anonymous(self) -> bool: ... + + +class Location: + lat: float + lon: float + x: float + y: float + + def __init__(self, arg2: float, arg3: float): ... # x, y ? + + def lat_without_check(self) -> float: ... + + def lon_without_check(self) -> float: ... + + def valid(self) -> bool: ... + + +class Node(OSMObject): + location: Location + + def replace(self) -> mutable.Node: ... + + +class NodeRef: + ref: OSMObjectIdType + location: Location + lat: float + lon: float + x: float + y: float + + +class Relation(OSMObject): + members: RelationMemberList + + def replace(self) -> mutable.Relation: ... + + +class RelationMember: + ref: OSMObjectIdType + type: str + role: str + + +class RelationMemberList: + def __len__(self) -> int: ... + + def __iter__(self) -> typing.Iterable[RelationMember]: ... + + +class Tag: + k: str + v: str + + +class TagList: + def __len__(self) -> int: ... + + def __getitem__(self, arg2: str) -> str: ... + + def __contains__(self, arg2: str) -> bool: ... + + def __iter__(self) -> typing.Iterable[Tag]: ... # ??? + + @typing.overload + def get(self, arg2) -> str: ... + + @typing.overload + def get(self, key: str, default: str) -> str: ... + + +class Way(OSMObject): + nodes: WayNodeList + + def ends_have_same_id(self) -> bool: ... + + def ends_have_same_location(self) -> bool: ... + + def is_closed(self) -> bool: ... + + def replace(self) -> mutable.Way: ... + + +class WayNodeList(NodeRefList): ... + + +class osm_entity_bits: + ALL: osm_entity_bits = ... + AREA: osm_entity_bits = ... + CHANGESET: osm_entity_bits = ... + NODE: osm_entity_bits = ... + NOTHING: osm_entity_bits = ... + OBJECT: osm_entity_bits = ... + RELATION: osm_entity_bits = ... + WAY: osm_entity_bits = ... + names: typing.Dict[str, osm_entity_bits] = ... + values: typing.Dict[int, osm_entity_bits] = ... diff --git a/src/osmium/osm/mutable.pyi b/src/osmium/osm/mutable.pyi new file mode 100644 index 00000000..2f9ade3f --- /dev/null +++ b/src/osmium/osm/mutable.pyi @@ -0,0 +1,53 @@ +import typing +from typing import Any, Optional + +from . import OSMObjectIdType, VersionType, ChangesetId, UidType, TagList +from ..replication.utils import Timestamp +from .. import osm + +LocationType = typing.Union[osm.Location, typing.Tuple[float, float]] +NodeListType = typing.Union[osm.WayNodeList, typing.List[osm.NodeRef], typing.List[int]] +RelationMembersType = typing.Union[ + osm.RelationMemberList, + typing.List[osm.RelationMember], + typing.List[typing.Tuple[str, int, str]] +] + + +class OSMObject: + id: OSMObjectIdType + version: VersionType + visible: bool + changeset: ChangesetId + timestamp: Timestamp + uid: UidType + tags: typing.Union[TagList, typing.Dict] + + def __init__(self, + base: Optional[Any] = ..., + id: Optional[OSMObjectIdType] = ..., + version: Optional[VersionType] = ..., + visible: Optional[bool] = ..., + changeset: Optional[ChangesetId] = ..., + timestamp: Optional[Timestamp] = ..., + uid: Optional[UidType] = ..., + tags: Optional[typing.Union[TagList, typing.Dict]] = ...) -> None: ... + + +class Node(OSMObject): + location: LocationType + + def __init__(self, base: Optional[osm.Node], location: Optional[LocationType], **attrs: Any) -> None: ... + + +class Way(OSMObject): + nodes: NodeListType = ... + + def __init__(self, base: Optional[osm.Way] = ..., nodes: Optional[NodeListType] = ..., **attrs: Any) -> None: ... + + +class Relation(OSMObject): + members: RelationMembersType = ... + + def __init__(self, base: Optional[osm.Relation] = ..., members: Optional[RelationMembersType] = ..., + **attrs: Any) -> None: ... diff --git a/src/osmium/replication/_replication.pyi b/src/osmium/replication/_replication.pyi new file mode 100644 index 00000000..e24b778d --- /dev/null +++ b/src/osmium/replication/_replication.pyi @@ -0,0 +1,4 @@ +from ..replication.utils import Timestamp + + +def newest_change_from_file(arg1: str) -> Timestamp: ... diff --git a/src/osmium/replication/server.pyi b/src/osmium/replication/server.pyi new file mode 100644 index 00000000..d3f35451 --- /dev/null +++ b/src/osmium/replication/server.pyi @@ -0,0 +1,38 @@ +import logging + +import typing +from typing import Optional + +from .. import MergeInputReader, BaseHandler +from ..replication.utils import Sequence, Timestamp + +log: logging.Logger + +OsmosisState = typing.NamedTuple('OsmosisState', [('sequence', Sequence), ('timestamp', Timestamp)]) +DownloadResult = typing.NamedTuple('DownloadResult', + [('id', Sequence), ('reader', MergeInputReader), ('newest', Sequence)]) + + +class ReplicationServer: + baseurl: str = ... + diff_type: str = ... + + def __init__(self, url: str, diff_type: str = ...) -> None: ... + + def collect_diffs(self, start_id: Sequence, max_size: int = ...) -> DownloadResult: ... + + def apply_diffs(self, handler: BaseHandler, start_id: Sequence, max_size: int = ..., idx: str = ..., + simplify: bool = ...) -> Optional[Sequence]: ... + + def apply_diffs_to_file(self, infile: str, outfile: str, start_id: Sequence, max_size: int = ..., + set_replication_header: bool = ...) -> Optional[typing.Tuple[Sequence, Sequence]]: ... + + def timestamp_to_sequence(self, timestamp: Timestamp, balanced_search: bool = ...) -> Optional[Sequence]: ... + + def get_state_info(self, seq: Optional[Sequence] = ...) -> OsmosisState: ... + + def get_diff_block(self, seq: Sequence) -> bytes: ... + + def get_state_url(self, seq: Sequence) -> str: ... + + def get_diff_url(self, seq: Sequence) -> str: ... diff --git a/src/osmium/replication/utils.pyi b/src/osmium/replication/utils.pyi new file mode 100644 index 00000000..57022218 --- /dev/null +++ b/src/osmium/replication/utils.pyi @@ -0,0 +1,15 @@ +import logging +from datetime import datetime + +import typing + +log: logging.Logger + +Sequence = typing.NewType('Sequence', int) +Timestamp = typing.NewType('Timestamp', datetime) + +ReplicationHeader = typing.NamedTuple('ReplicationHeader', + [('url', str), ('sequence', Sequence), ('timestamp', Timestamp)]) + + +def get_replication_header(fname: str) -> ReplicationHeader: ... From 8f0815534a16077a049f038e648c70b95cfc62f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Mon, 27 Aug 2018 22:49:04 +0200 Subject: [PATCH 02/16] Update annotations to 2.14.3 --- src/osmium/geom.pyi | 19 +++++++++++++++++++ src/osmium/replication/server.pyi | 12 ++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/osmium/geom.pyi b/src/osmium/geom.pyi index b1767bb0..92d1c0f2 100644 --- a/src/osmium/geom.pyi +++ b/src/osmium/geom.pyi @@ -33,6 +33,25 @@ class WKTFactory(BaseFactory): ... def haversine_distance(list: WayNodeList) -> float: ... +def lonlat_to_mercator(coordinates: Coordinates) -> float: ... + + +def mercator_to_lonlat(coordinates: Coordinates) -> float: ... + + +class Coordinates: + x: float + y: float + + @typing.overload + def __init__(self, lon: float, lat: float): ... + + @typing.overload + def __init__(self, location: Location): ... + + def valid(self) -> bool: ... + + class direction: BACKWARD: direction = ... FORWARD: direction = ... diff --git a/src/osmium/replication/server.pyi b/src/osmium/replication/server.pyi index d3f35451..b61f231d 100644 --- a/src/osmium/replication/server.pyi +++ b/src/osmium/replication/server.pyi @@ -1,4 +1,5 @@ import logging +from http.client import HTTPResponse import typing from typing import Optional @@ -19,13 +20,20 @@ class ReplicationServer: def __init__(self, url: str, diff_type: str = ...) -> None: ... + def open_url(self, url: str) -> HTTPResponse: ... + def collect_diffs(self, start_id: Sequence, max_size: int = ...) -> DownloadResult: ... def apply_diffs(self, handler: BaseHandler, start_id: Sequence, max_size: int = ..., idx: str = ..., simplify: bool = ...) -> Optional[Sequence]: ... - def apply_diffs_to_file(self, infile: str, outfile: str, start_id: Sequence, max_size: int = ..., - set_replication_header: bool = ...) -> Optional[typing.Tuple[Sequence, Sequence]]: ... + def apply_diffs_to_file(self, + infile: str, + outfile: str, + start_id: Sequence, + max_size: int = ..., + set_replication_header: bool = ..., + extra_headers: dict = ...) -> Optional[typing.Tuple[Sequence, Sequence]]: ... def timestamp_to_sequence(self, timestamp: Timestamp, balanced_search: bool = ...) -> Optional[Sequence]: ... From 816e9397dcaf818d60f4790f205bc6e52d4af7c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Sun, 21 Oct 2018 14:01:44 +0200 Subject: [PATCH 03/16] Add missing annotations --- src/osmium/_osmium.pyi | 46 +++++++++++++++---------------- src/osmium/index.pyi | 4 +-- src/osmium/io.pyi | 8 +++--- src/osmium/osm/_osm.pyi | 8 +++--- src/osmium/osm/mutable.py | 2 ++ src/osmium/replication/server.pyi | 2 +- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/osmium/_osmium.pyi b/src/osmium/_osmium.pyi index 9ccb9c19..6fa1ce44 100644 --- a/src/osmium/_osmium.pyi +++ b/src/osmium/_osmium.pyi @@ -1,7 +1,8 @@ import typing from .io import Reader, Writer -from .osm import Location, Node, Way, Relation, Area, Changeset, mutable +from .osm import Node, Way, Relation, Area, Changeset, mutable +from .index import LocationTable class InvalidLocationError(RuntimeError): ... @@ -11,52 +12,49 @@ class NotFoundError(KeyError): ... class MergeInputReader(Reader): - def add_buffer(self, buffer, format: str) -> int: ... + def add_buffer(self, buffer: bytes, format: str) -> int: ... def add_file(self, file: str) -> int: ... - def apply(self, handler: BaseHandler, idx: typing.Optional[str], simplify: bool = ...): ... + def apply(self, handler: BaseHandler, idx: typing.Optional[str], simplify: bool = ...) -> None: ... - def apply_to_reader(self, reader: Reader, writer: Writer, with_history: bool = ...): ... - - -LocationTable = typing.Mapping[int, Location] + def apply_to_reader(self, reader: Reader, writer: Writer, with_history: bool = ...) -> None: ... class NodeLocationsForWays(LocationTable): - def ignore_errors(self): ... + def ignore_errors(self) -> None: ... class BaseHandler: - def node(self, node: Node): ... + def node(self, node: Node) -> None: ... - def way(self, way: Way): ... + def way(self, way: Way) -> None: ... - def relation(self, relation: Relation): ... + def relation(self, relation: Relation) -> None: ... - def area(self, area: Area): ... + def area(self, area: Area) -> None: ... - def changeset(self, changeset: Changeset): ... + def changeset(self, changeset: Changeset) -> None: ... - def apply_start(self): ... + def apply_start(self) -> None: ... class SimpleHandler(BaseHandler): - def apply_buffer(self, buffer: bytes, format: str, locations: bool = ..., idx: str = ...): ... + def apply_buffer(self, buffer: bytes, format: str, locations: bool = ..., idx: str = ...) -> None: ... - def apply_file(self, filename: str, locations: bool = ..., idx: str = ...): ... + def apply_file(self, filename: str, locations: bool = ..., idx: str = ...) -> None: ... class SimpleWriter: - def __init__(self, arg2: str, arg3: typing.Optional[int]): ... # filename, buffer_size + def __init__(self, arg2: str, arg3: typing.Optional[int]) -> None: ... # filename, buffer_size - def add_node(self, node: typing.Union[Node, mutable.Node]): ... + def add_node(self, node: typing.Union[Node, mutable.Node]) -> None: ... - def add_relation(self, relation: typing.Union[Relation, mutable.Relation]): ... + def add_relation(self, relation: typing.Union[Relation, mutable.Relation]) -> None: ... - def add_way(self, way: typing.Union[Way, mutable.Way]): ... + def add_way(self, way: typing.Union[Way, mutable.Way]) -> None: ... - def close(self): ... + def close(self) -> None: ... class WriteHandler(BaseHandler): @@ -64,12 +62,12 @@ class WriteHandler(BaseHandler): @typing.overload -def apply(arg1: Reader, arg2: BaseHandler): ... # reader, write_handler +def apply(arg1: Reader, arg2: BaseHandler) -> None: ... # reader, write_handler @typing.overload -def apply(arg1: Reader, arg2: NodeLocationsForWays): ... # reader, nodes_idx +def apply(arg1: Reader, arg2: NodeLocationsForWays) -> None: ... # reader, nodes_idx @typing.overload -def apply(arg1: Reader, arg2: NodeLocationsForWays, arg3: BaseHandler): ... # reader, nodes_idx, write_handler +def apply(arg1: Reader, arg2: NodeLocationsForWays, arg3: BaseHandler) -> None: ... # reader, nodes_idx, write_handler diff --git a/src/osmium/index.pyi b/src/osmium/index.pyi index 60dfd3e2..e09b0a35 100644 --- a/src/osmium/index.pyi +++ b/src/osmium/index.pyi @@ -4,11 +4,11 @@ from .osm import Location class LocationTable: - def clear(self): ... + def clear(self) -> None: ... def get(self, id: int) -> Location: ... - def set(self, id: int, loc: Location): ... + def set(self, id: int, loc: Location) -> None: ... def used_memory(self) -> int: ... diff --git a/src/osmium/io.pyi b/src/osmium/io.pyi index 1cb46ada..d8a572a6 100644 --- a/src/osmium/io.pyi +++ b/src/osmium/io.pyi @@ -2,7 +2,7 @@ import typing from .osm import Box -osm_entity_bits = typing.NewType(int) +osm_entity_bits = typing.NewType('osm_entity_bits', int) class Header: @@ -12,7 +12,7 @@ class Header: def get(self, key: str, default: typing.Optional[str]) -> str: ... - def set(self, key: str, value: str): ... + def set(self, key: str, value: str) -> None: ... class Reader: @@ -22,7 +22,7 @@ class Reader: @typing.overload def __init__(self, arg2: str, arg3: osm_entity_bits): ... - def close(self): ... + def close(self) -> None: ... def eof(self) -> bool: ... @@ -36,4 +36,4 @@ class Writer: @typing.overload def __init__(self, arg2: str, arg3: Header): ... - def close(self): ... + def close(self) -> None: ... diff --git a/src/osmium/osm/_osm.pyi b/src/osmium/osm/_osm.pyi index b418f11d..1f025218 100644 --- a/src/osmium/osm/_osm.pyi +++ b/src/osmium/osm/_osm.pyi @@ -5,9 +5,9 @@ import typing from osmium.osm import mutable from osmium.replication.utils import Timestamp -OSMObjectIdType = typing.NewType('OSMObjectId', int) +OSMObjectIdType = typing.NewType('OSMObjectIdType', int) UnsginedOSMObjectIdType = typing.NewType('UnsginedOSMObjectIdType', OSMObjectIdType) -UidType = typing.NewType('UserId', int) +UidType = typing.NewType('UidType', int) VersionType = typing.NewType('VersionType', int) @@ -72,7 +72,7 @@ class Box: top_right: Location @typing.overload - def __init__(self): ... + def __init__(self) -> None: ... @typing.overload def __init__(self, arg2: float, arg3: float, arg4: float, arg5: float): ... @@ -173,7 +173,7 @@ class TagList: def __iter__(self) -> typing.Iterable[Tag]: ... # ??? @typing.overload - def get(self, arg2) -> str: ... + def get(self, arg: str) -> str: ... @typing.overload def get(self, key: str, default: str) -> str: ... diff --git a/src/osmium/osm/mutable.py b/src/osmium/osm/mutable.py index b700087e..ef5acd68 100644 --- a/src/osmium/osm/mutable.py +++ b/src/osmium/osm/mutable.py @@ -42,6 +42,8 @@ def __init__(self, base=None, location=None, **attrs): else: self.location = location if location is not None else base.location + def new(self, some): + return "new" class Way(OSMObject): """The mutable version of ``osmium.osm.Way``. It inherits all attributes diff --git a/src/osmium/replication/server.pyi b/src/osmium/replication/server.pyi index b61f231d..94d6cbaf 100644 --- a/src/osmium/replication/server.pyi +++ b/src/osmium/replication/server.pyi @@ -37,7 +37,7 @@ class ReplicationServer: def timestamp_to_sequence(self, timestamp: Timestamp, balanced_search: bool = ...) -> Optional[Sequence]: ... - def get_state_info(self, seq: Optional[Sequence] = ...) -> OsmosisState: ... + def get_state_info(self, seq: Optional[Sequence] = ...) -> Optional[OsmosisState]: ... def get_diff_block(self, seq: Sequence) -> bytes: ... From baceba9ec7bed6e56c1b35e6b64245563ec8f964 Mon Sep 17 00:00:00 2001 From: Wiktor Niesiobedzki Date: Sun, 6 May 2018 01:07:34 +0200 Subject: [PATCH 04/16] Typing information for pyosmium --- src/osmium/_osmium.pyi | 75 +++++++++ src/osmium/geom.pyi | 47 ++++++ src/osmium/index.pyi | 19 +++ src/osmium/io.pyi | 39 +++++ src/osmium/osm/__init__.pyi | 13 ++ src/osmium/osm/_osm.pyi | 207 ++++++++++++++++++++++++ src/osmium/osm/mutable.pyi | 53 ++++++ src/osmium/replication/_replication.pyi | 4 + src/osmium/replication/server.pyi | 38 +++++ src/osmium/replication/utils.pyi | 15 ++ 10 files changed, 510 insertions(+) create mode 100644 src/osmium/_osmium.pyi create mode 100644 src/osmium/geom.pyi create mode 100644 src/osmium/index.pyi create mode 100644 src/osmium/io.pyi create mode 100644 src/osmium/osm/__init__.pyi create mode 100644 src/osmium/osm/_osm.pyi create mode 100644 src/osmium/osm/mutable.pyi create mode 100644 src/osmium/replication/_replication.pyi create mode 100644 src/osmium/replication/server.pyi create mode 100644 src/osmium/replication/utils.pyi diff --git a/src/osmium/_osmium.pyi b/src/osmium/_osmium.pyi new file mode 100644 index 00000000..9ccb9c19 --- /dev/null +++ b/src/osmium/_osmium.pyi @@ -0,0 +1,75 @@ +import typing + +from .io import Reader, Writer +from .osm import Location, Node, Way, Relation, Area, Changeset, mutable + + +class InvalidLocationError(RuntimeError): ... + + +class NotFoundError(KeyError): ... + + +class MergeInputReader(Reader): + def add_buffer(self, buffer, format: str) -> int: ... + + def add_file(self, file: str) -> int: ... + + def apply(self, handler: BaseHandler, idx: typing.Optional[str], simplify: bool = ...): ... + + def apply_to_reader(self, reader: Reader, writer: Writer, with_history: bool = ...): ... + + +LocationTable = typing.Mapping[int, Location] + + +class NodeLocationsForWays(LocationTable): + def ignore_errors(self): ... + + +class BaseHandler: + def node(self, node: Node): ... + + def way(self, way: Way): ... + + def relation(self, relation: Relation): ... + + def area(self, area: Area): ... + + def changeset(self, changeset: Changeset): ... + + def apply_start(self): ... + + +class SimpleHandler(BaseHandler): + def apply_buffer(self, buffer: bytes, format: str, locations: bool = ..., idx: str = ...): ... + + def apply_file(self, filename: str, locations: bool = ..., idx: str = ...): ... + + +class SimpleWriter: + def __init__(self, arg2: str, arg3: typing.Optional[int]): ... # filename, buffer_size + + def add_node(self, node: typing.Union[Node, mutable.Node]): ... + + def add_relation(self, relation: typing.Union[Relation, mutable.Relation]): ... + + def add_way(self, way: typing.Union[Way, mutable.Way]): ... + + def close(self): ... + + +class WriteHandler(BaseHandler): + def __init__(self, arg2: str, arg3: typing.Optional[int]): ... # filename, buffer_size + + +@typing.overload +def apply(arg1: Reader, arg2: BaseHandler): ... # reader, write_handler + + +@typing.overload +def apply(arg1: Reader, arg2: NodeLocationsForWays): ... # reader, nodes_idx + + +@typing.overload +def apply(arg1: Reader, arg2: NodeLocationsForWays, arg3: BaseHandler): ... # reader, nodes_idx, write_handler diff --git a/src/osmium/geom.pyi b/src/osmium/geom.pyi new file mode 100644 index 00000000..b1767bb0 --- /dev/null +++ b/src/osmium/geom.pyi @@ -0,0 +1,47 @@ +import typing + +from .osm import WayNodeList, Area, Location, Node, NodeRef + + +class BaseFactory: + epsg: int + proj_string: str + + def create_linestring(self, list: WayNodeList, use_nodes: use_nodes, direction: direction) -> str: ... + + def create_multipolygon(self, area: Area) -> str: ... + + @typing.overload + def create_point(self, location: Location) -> str: ... + + @typing.overload + def create_point(self, node: Node) -> str: ... + + @typing.overload + def create_point(self, ref: NodeRef) -> str: ... + + +class GeoJSONFactory(BaseFactory): ... + + +class WKBFactory(BaseFactory): ... + + +class WKTFactory(BaseFactory): ... + + +def haversine_distance(list: WayNodeList) -> float: ... + + +class direction: + BACKWARD: direction = ... + FORWARD: direction = ... + names: typing.Dict[str, direction] = ... + values: typing.Dict[int, direction] = ... + + +class use_nodes: + ALL: use_nodes = ... + UNIQUE: use_nodes = ... + names: typing.Dict[str, use_nodes] = ... + values: typing.Dict[int, use_nodes] = ... diff --git a/src/osmium/index.pyi b/src/osmium/index.pyi new file mode 100644 index 00000000..60dfd3e2 --- /dev/null +++ b/src/osmium/index.pyi @@ -0,0 +1,19 @@ +import typing + +from .osm import Location + + +class LocationTable: + def clear(self): ... + + def get(self, id: int) -> Location: ... + + def set(self, id: int, loc: Location): ... + + def used_memory(self) -> int: ... + + +def create_map(map_type: str) -> LocationTable: ... + + +def map_types() -> typing.List[str]: ... diff --git a/src/osmium/io.pyi b/src/osmium/io.pyi new file mode 100644 index 00000000..1cb46ada --- /dev/null +++ b/src/osmium/io.pyi @@ -0,0 +1,39 @@ +import typing + +from .osm import Box + +osm_entity_bits = typing.NewType(int) + + +class Header: + has_multiple_object_versions: bool + + def box(self) -> Box: ... + + def get(self, key: str, default: typing.Optional[str]) -> str: ... + + def set(self, key: str, value: str): ... + + +class Reader: + @typing.overload + def __init__(self, arg2: str): ... + + @typing.overload + def __init__(self, arg2: str, arg3: osm_entity_bits): ... + + def close(self): ... + + def eof(self) -> bool: ... + + def header(self) -> Header: ... + + +class Writer: + @typing.overload + def __init__(self, arg2: str): ... + + @typing.overload + def __init__(self, arg2: str, arg3: Header): ... + + def close(self): ... diff --git a/src/osmium/osm/__init__.pyi b/src/osmium/osm/__init__.pyi new file mode 100644 index 00000000..09461d8d --- /dev/null +++ b/src/osmium/osm/__init__.pyi @@ -0,0 +1,13 @@ +from typing import Any + +from . import mutable +from ._osm import * + + +def create_mutable_node(node: Node, **args: Any) -> mutable.Node: ... + + +def create_mutable_way(way: Way, **args: Any) -> mutable.Way: ... + + +def create_mutable_relation(rel: Relation, **args: Any) -> mutable.Relation: ... diff --git a/src/osmium/osm/_osm.pyi b/src/osmium/osm/_osm.pyi new file mode 100644 index 00000000..b418f11d --- /dev/null +++ b/src/osmium/osm/_osm.pyi @@ -0,0 +1,207 @@ +import datetime + +import typing + +from osmium.osm import mutable +from osmium.replication.utils import Timestamp + +OSMObjectIdType = typing.NewType('OSMObjectId', int) +UnsginedOSMObjectIdType = typing.NewType('UnsginedOSMObjectIdType', OSMObjectIdType) +UidType = typing.NewType('UserId', int) +VersionType = typing.NewType('VersionType', int) + + +class OSMObject: + id: OSMObjectIdType + deleted: bool + visible: bool + version: VersionType + changeset: ChangesetId + uid: UidType + timestamp: Timestamp + user: str + tags: TagList + + def positive_id(self) -> UnsginedOSMObjectIdType: ... + + def user_is_anonymous(self) -> bool: ... + + +class NodeRefList: + def __len__(self) -> int: ... + + def __getitem__(self, arg2: int) -> NodeRef: ... + + def __iter__(self) -> typing.Iterable[NodeRef]: ... + + def ends_have_same_id(self) -> bool: ... + + def ends_have_same_location(self) -> bool: ... + + def is_closed(self) -> bool: ... + + +class InnerRing(NodeRefList): ... + + +InnerRingIterator = typing.Iterable[InnerRing] + + +class OuterRing(NodeRefList): ... + + +OuterRingIterator = typing.Iterable[OuterRing] + + +class Area(OSMObject): + def from_way(self) -> bool: ... + + def orig_id(self) -> OSMObjectIdType: ... + + def is_multipolygon(self) -> bool: ... + + def num_rings(self) -> typing.Tuple[int, int]: ... + + def outer_rings(self) -> OuterRingIterator: ... + + def inner_rings(self) -> InnerRingIterator: ... + + +class Box: + bottom_left: Location + top_right: Location + + @typing.overload + def __init__(self): ... + + @typing.overload + def __init__(self, arg2: float, arg3: float, arg4: float, arg5: float): ... + + @typing.overload + def __init__(self, arg2: Location, arg3: Location): ... + + def contains(self, location: Location) -> bool: ... + + @typing.overload + def extend(self, arg2: Location) -> Box: ... + + @typing.overload + def extend(self, arg2: Box) -> Box: ... + + def size(self) -> float: ... + + def valid(self) -> bool: ... + + +ChangesetId = typing.NewType('ChangesetId', int) + + +class Changeset: + id: ChangesetId + uid: UidType + created_at: datetime.datetime # ??? + closed_at: datetime.datetime # ??? + open: bool + num_changes: int + bounds: Box + user: str + tags: TagList + + def user_is_anonymous(self) -> bool: ... + + +class Location: + lat: float + lon: float + x: float + y: float + + def __init__(self, arg2: float, arg3: float): ... # x, y ? + + def lat_without_check(self) -> float: ... + + def lon_without_check(self) -> float: ... + + def valid(self) -> bool: ... + + +class Node(OSMObject): + location: Location + + def replace(self) -> mutable.Node: ... + + +class NodeRef: + ref: OSMObjectIdType + location: Location + lat: float + lon: float + x: float + y: float + + +class Relation(OSMObject): + members: RelationMemberList + + def replace(self) -> mutable.Relation: ... + + +class RelationMember: + ref: OSMObjectIdType + type: str + role: str + + +class RelationMemberList: + def __len__(self) -> int: ... + + def __iter__(self) -> typing.Iterable[RelationMember]: ... + + +class Tag: + k: str + v: str + + +class TagList: + def __len__(self) -> int: ... + + def __getitem__(self, arg2: str) -> str: ... + + def __contains__(self, arg2: str) -> bool: ... + + def __iter__(self) -> typing.Iterable[Tag]: ... # ??? + + @typing.overload + def get(self, arg2) -> str: ... + + @typing.overload + def get(self, key: str, default: str) -> str: ... + + +class Way(OSMObject): + nodes: WayNodeList + + def ends_have_same_id(self) -> bool: ... + + def ends_have_same_location(self) -> bool: ... + + def is_closed(self) -> bool: ... + + def replace(self) -> mutable.Way: ... + + +class WayNodeList(NodeRefList): ... + + +class osm_entity_bits: + ALL: osm_entity_bits = ... + AREA: osm_entity_bits = ... + CHANGESET: osm_entity_bits = ... + NODE: osm_entity_bits = ... + NOTHING: osm_entity_bits = ... + OBJECT: osm_entity_bits = ... + RELATION: osm_entity_bits = ... + WAY: osm_entity_bits = ... + names: typing.Dict[str, osm_entity_bits] = ... + values: typing.Dict[int, osm_entity_bits] = ... diff --git a/src/osmium/osm/mutable.pyi b/src/osmium/osm/mutable.pyi new file mode 100644 index 00000000..2f9ade3f --- /dev/null +++ b/src/osmium/osm/mutable.pyi @@ -0,0 +1,53 @@ +import typing +from typing import Any, Optional + +from . import OSMObjectIdType, VersionType, ChangesetId, UidType, TagList +from ..replication.utils import Timestamp +from .. import osm + +LocationType = typing.Union[osm.Location, typing.Tuple[float, float]] +NodeListType = typing.Union[osm.WayNodeList, typing.List[osm.NodeRef], typing.List[int]] +RelationMembersType = typing.Union[ + osm.RelationMemberList, + typing.List[osm.RelationMember], + typing.List[typing.Tuple[str, int, str]] +] + + +class OSMObject: + id: OSMObjectIdType + version: VersionType + visible: bool + changeset: ChangesetId + timestamp: Timestamp + uid: UidType + tags: typing.Union[TagList, typing.Dict] + + def __init__(self, + base: Optional[Any] = ..., + id: Optional[OSMObjectIdType] = ..., + version: Optional[VersionType] = ..., + visible: Optional[bool] = ..., + changeset: Optional[ChangesetId] = ..., + timestamp: Optional[Timestamp] = ..., + uid: Optional[UidType] = ..., + tags: Optional[typing.Union[TagList, typing.Dict]] = ...) -> None: ... + + +class Node(OSMObject): + location: LocationType + + def __init__(self, base: Optional[osm.Node], location: Optional[LocationType], **attrs: Any) -> None: ... + + +class Way(OSMObject): + nodes: NodeListType = ... + + def __init__(self, base: Optional[osm.Way] = ..., nodes: Optional[NodeListType] = ..., **attrs: Any) -> None: ... + + +class Relation(OSMObject): + members: RelationMembersType = ... + + def __init__(self, base: Optional[osm.Relation] = ..., members: Optional[RelationMembersType] = ..., + **attrs: Any) -> None: ... diff --git a/src/osmium/replication/_replication.pyi b/src/osmium/replication/_replication.pyi new file mode 100644 index 00000000..e24b778d --- /dev/null +++ b/src/osmium/replication/_replication.pyi @@ -0,0 +1,4 @@ +from ..replication.utils import Timestamp + + +def newest_change_from_file(arg1: str) -> Timestamp: ... diff --git a/src/osmium/replication/server.pyi b/src/osmium/replication/server.pyi new file mode 100644 index 00000000..d3f35451 --- /dev/null +++ b/src/osmium/replication/server.pyi @@ -0,0 +1,38 @@ +import logging + +import typing +from typing import Optional + +from .. import MergeInputReader, BaseHandler +from ..replication.utils import Sequence, Timestamp + +log: logging.Logger + +OsmosisState = typing.NamedTuple('OsmosisState', [('sequence', Sequence), ('timestamp', Timestamp)]) +DownloadResult = typing.NamedTuple('DownloadResult', + [('id', Sequence), ('reader', MergeInputReader), ('newest', Sequence)]) + + +class ReplicationServer: + baseurl: str = ... + diff_type: str = ... + + def __init__(self, url: str, diff_type: str = ...) -> None: ... + + def collect_diffs(self, start_id: Sequence, max_size: int = ...) -> DownloadResult: ... + + def apply_diffs(self, handler: BaseHandler, start_id: Sequence, max_size: int = ..., idx: str = ..., + simplify: bool = ...) -> Optional[Sequence]: ... + + def apply_diffs_to_file(self, infile: str, outfile: str, start_id: Sequence, max_size: int = ..., + set_replication_header: bool = ...) -> Optional[typing.Tuple[Sequence, Sequence]]: ... + + def timestamp_to_sequence(self, timestamp: Timestamp, balanced_search: bool = ...) -> Optional[Sequence]: ... + + def get_state_info(self, seq: Optional[Sequence] = ...) -> OsmosisState: ... + + def get_diff_block(self, seq: Sequence) -> bytes: ... + + def get_state_url(self, seq: Sequence) -> str: ... + + def get_diff_url(self, seq: Sequence) -> str: ... diff --git a/src/osmium/replication/utils.pyi b/src/osmium/replication/utils.pyi new file mode 100644 index 00000000..57022218 --- /dev/null +++ b/src/osmium/replication/utils.pyi @@ -0,0 +1,15 @@ +import logging +from datetime import datetime + +import typing + +log: logging.Logger + +Sequence = typing.NewType('Sequence', int) +Timestamp = typing.NewType('Timestamp', datetime) + +ReplicationHeader = typing.NamedTuple('ReplicationHeader', + [('url', str), ('sequence', Sequence), ('timestamp', Timestamp)]) + + +def get_replication_header(fname: str) -> ReplicationHeader: ... From 66b0090117bf32d0b5c336831246707bbac8c36d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Mon, 27 Aug 2018 22:49:04 +0200 Subject: [PATCH 05/16] Update annotations to 2.14.3 --- src/osmium/geom.pyi | 19 +++++++++++++++++++ src/osmium/replication/server.pyi | 12 ++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/osmium/geom.pyi b/src/osmium/geom.pyi index b1767bb0..92d1c0f2 100644 --- a/src/osmium/geom.pyi +++ b/src/osmium/geom.pyi @@ -33,6 +33,25 @@ class WKTFactory(BaseFactory): ... def haversine_distance(list: WayNodeList) -> float: ... +def lonlat_to_mercator(coordinates: Coordinates) -> float: ... + + +def mercator_to_lonlat(coordinates: Coordinates) -> float: ... + + +class Coordinates: + x: float + y: float + + @typing.overload + def __init__(self, lon: float, lat: float): ... + + @typing.overload + def __init__(self, location: Location): ... + + def valid(self) -> bool: ... + + class direction: BACKWARD: direction = ... FORWARD: direction = ... diff --git a/src/osmium/replication/server.pyi b/src/osmium/replication/server.pyi index d3f35451..b61f231d 100644 --- a/src/osmium/replication/server.pyi +++ b/src/osmium/replication/server.pyi @@ -1,4 +1,5 @@ import logging +from http.client import HTTPResponse import typing from typing import Optional @@ -19,13 +20,20 @@ class ReplicationServer: def __init__(self, url: str, diff_type: str = ...) -> None: ... + def open_url(self, url: str) -> HTTPResponse: ... + def collect_diffs(self, start_id: Sequence, max_size: int = ...) -> DownloadResult: ... def apply_diffs(self, handler: BaseHandler, start_id: Sequence, max_size: int = ..., idx: str = ..., simplify: bool = ...) -> Optional[Sequence]: ... - def apply_diffs_to_file(self, infile: str, outfile: str, start_id: Sequence, max_size: int = ..., - set_replication_header: bool = ...) -> Optional[typing.Tuple[Sequence, Sequence]]: ... + def apply_diffs_to_file(self, + infile: str, + outfile: str, + start_id: Sequence, + max_size: int = ..., + set_replication_header: bool = ..., + extra_headers: dict = ...) -> Optional[typing.Tuple[Sequence, Sequence]]: ... def timestamp_to_sequence(self, timestamp: Timestamp, balanced_search: bool = ...) -> Optional[Sequence]: ... From 32bca485839e75c738318253f0b51016852fc523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Wed, 30 Jan 2019 23:28:55 +0100 Subject: [PATCH 06/16] Move type information to py files --- build-requirements.txt | 1 + src/osmium/osm/__init__.py | 11 +++++++ src/osmium/osm/__init__.pyi | 13 -------- src/osmium/osm/mutable.py | 49 ++++++++++++++++++++++------ src/osmium/osm/mutable.pyi | 53 ------------------------------- src/osmium/replication/server.py | 27 +++++++++++++--- src/osmium/replication/server.pyi | 46 --------------------------- src/osmium/replication/utils.py | 20 +++++++++--- src/osmium/replication/utils.pyi | 15 --------- test-requirements.txt | 2 ++ 10 files changed, 92 insertions(+), 145 deletions(-) create mode 100644 build-requirements.txt delete mode 100644 src/osmium/osm/__init__.pyi delete mode 100644 src/osmium/osm/mutable.pyi delete mode 100644 src/osmium/replication/server.pyi delete mode 100644 src/osmium/replication/utils.pyi create mode 100644 test-requirements.txt diff --git a/build-requirements.txt b/build-requirements.txt new file mode 100644 index 00000000..f0aa93ac --- /dev/null +++ b/build-requirements.txt @@ -0,0 +1 @@ +mypy diff --git a/src/osmium/osm/__init__.py b/src/osmium/osm/__init__.py index c9882278..77ca2400 100644 --- a/src/osmium/osm/__init__.py +++ b/src/osmium/osm/__init__.py @@ -1,27 +1,38 @@ from ._osm import * import osmium.osm.mutable +MYPY = False +if MYPY: + import typing + + def create_mutable_node(node, **args): + # type: (Node, typing.Any) -> osmium.osm.mutable.Node """ Create a mutable node replacing the properties given in the named parameters. Note that this function only creates a shallow copy which is still bound to the scope of the original object. """ return osmium.osm.mutable.Node(base=node, **args) + def create_mutable_way(way, **args): + # type: (Way, typing.Any) -> osmium.osm.mutable.Way """ Create a mutable way replacing the properties given in the named parameters. Note that this function only creates a shallow copy which is still bound to the scope of the original object. """ return osmium.osm.mutable.Way(base=way, **args) + def create_mutable_relation(rel, **args): + # type: (Relation, typing.Any) -> osmium.osm.mutable.Relation """ Create a mutable relation replacing the properties given in the named parameters. Note that this function only creates a shallow copy which is still bound to the scope of the original object. """ return osmium.osm.mutable.Relation(base=rel, **args) + Node.replace = create_mutable_node Way.replace = create_mutable_way Relation.replace = create_mutable_relation diff --git a/src/osmium/osm/__init__.pyi b/src/osmium/osm/__init__.pyi deleted file mode 100644 index 09461d8d..00000000 --- a/src/osmium/osm/__init__.pyi +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Any - -from . import mutable -from ._osm import * - - -def create_mutable_node(node: Node, **args: Any) -> mutable.Node: ... - - -def create_mutable_way(way: Way, **args: Any) -> mutable.Way: ... - - -def create_mutable_relation(rel: Relation, **args: Any) -> mutable.Relation: ... diff --git a/src/osmium/osm/mutable.py b/src/osmium/osm/mutable.py index b700087e..e061f1cd 100644 --- a/src/osmium/osm/mutable.py +++ b/src/osmium/osm/mutable.py @@ -1,3 +1,27 @@ +MYPY = False +if MYPY: + import typing + from typing import Optional + from . import TagList + from ..replication.utils import Timestamp + from . import Location + from .. import osm + + OSMObjectIdType = typing.NewType('OSMObjectId', int) + VersionType = typing.NewType('VersionType', int) + UnsginedOSMObjectIdType = typing.NewType('UnsginedOSMObjectIdType', OSMObjectIdType) + UidType = typing.NewType('UserId', int) + ChangesetId = typing.NewType('ChangesetId', int) + LocationType = typing.Union[Location, typing.Tuple[float, float]] + + NodeListType = typing.Union[osm.WayNodeList, typing.List[osm.NodeRef], typing.List[int]] + RelationMembersType = typing.Union[ + osm.RelationMemberList, + typing.List[osm.RelationMember], + typing.List[typing.Tuple[str, int, str]] + ] + + class OSMObject(object): """Mutable version of ``osmium.osm.OSMObject``. It exposes the following attributes ``id``, ``version``, ``visible``, ``changeset``, ``timestamp``, @@ -11,14 +35,15 @@ class OSMObject(object): def __init__(self, base=None, id=None, version=None, visible=None, changeset=None, timestamp=None, uid=None, tags=None): + # type: (Optional[typing.Any], Optional[OSMObjectIdType], Optional[VersionType], bool, ChangesetId, Timestamp, UidType, typing.Union[TagList, typing.Dict[str, str]]) -> None if base is None: - self.id = id - self.version = version - self.visible = visible - self.changeset = changeset - self.timestamp = timestamp - self.uid = uid - self.tags = tags + self.id = id # type: OSMObjectIdType + self.version = version # type: VersionType + self.visible = visible # type: bool + self.changeset = changeset # type: ChangesetId + self.timestamp = timestamp # type: Timestamp + self.uid = uid # type: UidType + self.tags = tags # typing.Union[TagList, typing.Dict[str, str]] else: self.id = base.id if id is None else id self.version = base.version if version is None else version @@ -36,9 +61,10 @@ class Node(OSMObject): """ def __init__(self, base=None, location=None, **attrs): + # type: (Optional[osm.Node], Optional[LocationType], typing.Any) -> None OSMObject.__init__(self, base=base, **attrs) if base is None: - self.location = location + self.location = location # type: LocationType else: self.location = location if location is not None else base.location @@ -51,12 +77,14 @@ class Way(OSMObject): """ def __init__(self, base=None, nodes=None, **attrs): + # type: (Optional[osm.Way], Optional[NodeListType], typing.Any) -> None OSMObject.__init__(self, base=base, **attrs) if base is None: - self.nodes = nodes + self.nodes = nodes # type: NodeListType else: self.nodes = nodes if nodes is not None else base.nodes + class Relation(OSMObject): """The mutable version of ``osmium.osm.Relation``. It inherits all attributes from osmium.osm.mutable.OSMObject and adds a `members` attribute. This @@ -66,9 +94,10 @@ class Relation(OSMObject): """ def __init__(self, base=None, members=None, **attrs): + # type: (Optional[osm.Relation], Optional[RelationMembersType], typing.Any) -> None OSMObject.__init__(self, base=base, **attrs) if base is None: - self.members = members + self.members = members # type: RelationMembersType else: self.members = members if members is not None else base.members diff --git a/src/osmium/osm/mutable.pyi b/src/osmium/osm/mutable.pyi deleted file mode 100644 index 2f9ade3f..00000000 --- a/src/osmium/osm/mutable.pyi +++ /dev/null @@ -1,53 +0,0 @@ -import typing -from typing import Any, Optional - -from . import OSMObjectIdType, VersionType, ChangesetId, UidType, TagList -from ..replication.utils import Timestamp -from .. import osm - -LocationType = typing.Union[osm.Location, typing.Tuple[float, float]] -NodeListType = typing.Union[osm.WayNodeList, typing.List[osm.NodeRef], typing.List[int]] -RelationMembersType = typing.Union[ - osm.RelationMemberList, - typing.List[osm.RelationMember], - typing.List[typing.Tuple[str, int, str]] -] - - -class OSMObject: - id: OSMObjectIdType - version: VersionType - visible: bool - changeset: ChangesetId - timestamp: Timestamp - uid: UidType - tags: typing.Union[TagList, typing.Dict] - - def __init__(self, - base: Optional[Any] = ..., - id: Optional[OSMObjectIdType] = ..., - version: Optional[VersionType] = ..., - visible: Optional[bool] = ..., - changeset: Optional[ChangesetId] = ..., - timestamp: Optional[Timestamp] = ..., - uid: Optional[UidType] = ..., - tags: Optional[typing.Union[TagList, typing.Dict]] = ...) -> None: ... - - -class Node(OSMObject): - location: LocationType - - def __init__(self, base: Optional[osm.Node], location: Optional[LocationType], **attrs: Any) -> None: ... - - -class Way(OSMObject): - nodes: NodeListType = ... - - def __init__(self, base: Optional[osm.Way] = ..., nodes: Optional[NodeListType] = ..., **attrs: Any) -> None: ... - - -class Relation(OSMObject): - members: RelationMembersType = ... - - def __init__(self, base: Optional[osm.Relation] = ..., members: Optional[RelationMembersType] = ..., - **attrs: Any) -> None: ... diff --git a/src/osmium/replication/server.py b/src/osmium/replication/server.py index 40de54dc..d30cbd06 100644 --- a/src/osmium/replication/server.py +++ b/src/osmium/replication/server.py @@ -18,6 +18,17 @@ import logging +MYPY = False +if MYPY: + import typing + from ..replication.utils import Sequence, Timestamp + from http.client import HTTPResponse + from .. import BaseHandler + + OsmosisState = typing.NamedTuple('OsmosisState', [('sequence', Sequence), ('timestamp', Timestamp)]) + DownloadResult = typing.NamedTuple('DownloadResult', + [('id', Sequence), ('reader', MergeInputReader), ('newest', Sequence)]) + log = logging.getLogger('pyosmium') log.addHandler(logging.NullHandler()) @@ -31,10 +42,12 @@ class ReplicationServer(object): """ def __init__(self, url, diff_type='osc.gz'): - self.baseurl = url - self.diff_type = diff_type + # type: (str, str) -> None + self.baseurl = url # type: str + self.diff_type = diff_type # type: str def open_url(self, url): + # type: (str) -> HTTPResponse """ Download a resource from the given URL and return a byte sequence of the content. @@ -54,6 +67,7 @@ def my_open_url(self, url): return urlrequest.urlopen(url) def collect_diffs(self, start_id, max_size=1024): + # type: (Sequence, int) -> typing.Optional[DownloadResult] """ Create a MergeInputReader and download diffs starting with sequence id `start_id` into it. `max_size` restricts the number of diffs that are downloaded. The download @@ -98,6 +112,7 @@ def collect_diffs(self, start_id, max_size=1024): return DownloadResult(current_id - 1, rd, newest.sequence) def apply_diffs(self, handler, start_id, max_size=1024, idx="", simplify=True): + # type: (BaseHandler, Sequence, int, str, bool) -> typing.Optional[Sequence] """ Download diffs starting with sequence id `start_id`, merge them together and then apply them to handler `handler`. `max_size` restricts the number of diffs that are downloaded. The download @@ -133,6 +148,7 @@ def apply_diffs(self, handler, start_id, max_size=1024, idx="", simplify=True): def apply_diffs_to_file(self, infile, outfile, start_id, max_size=1024, set_replication_header=True, extra_headers={}): + # type: (str, str, Sequence, int, bool, typing.Dict[str, str]) -> typing.Optional[typing.Tuple[Sequence, Sequence]] """ Download diffs starting with sequence id `start_id`, merge them with the data from the OSM file named `infile` and write the result into a file with the name `outfile`. The output file must not yet @@ -183,8 +199,8 @@ def apply_diffs_to_file(self, infile, outfile, start_id, max_size=1024, return (diffs.id, diffs.newest) - def timestamp_to_sequence(self, timestamp, balanced_search=False): + # type: (Timestamp, bool) -> typing.Optional[Sequence] """ Get the sequence number of the replication file that contains the given timestamp. The search algorithm is optimised for replication servers that publish updates in regular intervals. For servers @@ -265,8 +281,8 @@ def timestamp_to_sequence(self, timestamp, balanced_search=False): if lower.sequence + 1 >= upper.sequence: return lower.sequence - def get_state_info(self, seq=None): + # type: (typing.Optional[Sequence]) -> typing.Optional[OsmosisState] """ Downloads and returns the state information for the given sequence. If the download is successful, a namedtuple with `sequence` and `timestamp` is returned, otherwise the function @@ -302,6 +318,7 @@ def get_state_info(self, seq=None): return OsmosisState(sequence=seq, timestamp=ts) def get_diff_block(self, seq): + # type: (Sequence) -> bytes """ Downloads the diff with the given sequence number and returns it as a byte sequence. Throws a :code:`urllib.error.HTTPError` (or :code:`urllib2.HTTPError` in python2) @@ -311,6 +328,7 @@ def get_diff_block(self, seq): def get_state_url(self, seq): + # type: (Sequence) -> str """ Returns the URL of the state.txt files for a given sequence id. If seq is `None` the URL for the latest state info is returned, @@ -325,6 +343,7 @@ def get_state_url(self, seq): def get_diff_url(self, seq): + # type: (Sequence) -> str """ Returns the URL to the diff file for the given sequence id. """ return '%s/%03i/%03i/%03i.%s' % (self.baseurl, diff --git a/src/osmium/replication/server.pyi b/src/osmium/replication/server.pyi deleted file mode 100644 index b61f231d..00000000 --- a/src/osmium/replication/server.pyi +++ /dev/null @@ -1,46 +0,0 @@ -import logging -from http.client import HTTPResponse - -import typing -from typing import Optional - -from .. import MergeInputReader, BaseHandler -from ..replication.utils import Sequence, Timestamp - -log: logging.Logger - -OsmosisState = typing.NamedTuple('OsmosisState', [('sequence', Sequence), ('timestamp', Timestamp)]) -DownloadResult = typing.NamedTuple('DownloadResult', - [('id', Sequence), ('reader', MergeInputReader), ('newest', Sequence)]) - - -class ReplicationServer: - baseurl: str = ... - diff_type: str = ... - - def __init__(self, url: str, diff_type: str = ...) -> None: ... - - def open_url(self, url: str) -> HTTPResponse: ... - - def collect_diffs(self, start_id: Sequence, max_size: int = ...) -> DownloadResult: ... - - def apply_diffs(self, handler: BaseHandler, start_id: Sequence, max_size: int = ..., idx: str = ..., - simplify: bool = ...) -> Optional[Sequence]: ... - - def apply_diffs_to_file(self, - infile: str, - outfile: str, - start_id: Sequence, - max_size: int = ..., - set_replication_header: bool = ..., - extra_headers: dict = ...) -> Optional[typing.Tuple[Sequence, Sequence]]: ... - - def timestamp_to_sequence(self, timestamp: Timestamp, balanced_search: bool = ...) -> Optional[Sequence]: ... - - def get_state_info(self, seq: Optional[Sequence] = ...) -> OsmosisState: ... - - def get_diff_block(self, seq: Sequence) -> bytes: ... - - def get_state_url(self, seq: Sequence) -> str: ... - - def get_diff_url(self, seq: Sequence) -> str: ... diff --git a/src/osmium/replication/utils.py b/src/osmium/replication/utils.py index 48cdc9ce..17a1c468 100644 --- a/src/osmium/replication/utils.py +++ b/src/osmium/replication/utils.py @@ -7,12 +7,24 @@ from osmium.osm import NOTHING from sys import version_info as python_version -log = logging.getLogger('pyosmium') +MYPY = False +if MYPY: + import typing + import datetime + + Sequence = typing.NewType('Sequence', int) + Timestamp = typing.NewType('Timestamp', datetime.datetime) + ReplicationHeader = typing.NamedTuple('ReplicationHeader', + [('url', str), ('sequence', Sequence), ('timestamp', Timestamp)]) + +log = logging.getLogger('pyosmium') # type: logging.Logger ReplicationHeader = namedtuple('ReplicationHeader', ['url', 'sequence', 'timestamp']) + def get_replication_header(fname): + # type: (str) -> ReplicationHeader """ Scans the given file for an Osmosis replication header. It returns a namedtuple with `url`, `sequence` and `timestamp`. Each or all fields may be None, if the piece of information is not avilable. If any of @@ -25,7 +37,7 @@ def get_replication_header(fname): r = oreader(fname, NOTHING) h = r.header() - ts = h.get("osmosis_replication_timestamp") + ts = h.get("osmosis_replication_timestamp") # type: Timestamp url = h.get("osmosis_replication_base_url") if url or ts: @@ -34,7 +46,7 @@ def get_replication_header(fname): if url: log.debug("Replication URL: %s" % url) # the sequence ID is only considered valid, if an URL is given - seq = h.get("osmosis_replication_sequence_number") + seq = h.get("osmosis_replication_sequence_number") # type: Sequence if seq: log.debug("Replication sequence: %s" % seq) try: @@ -54,7 +66,7 @@ def get_replication_header(fname): if ts: log.debug("Replication timestamp: %s" % ts) try: - ts = dt.datetime.strptime(ts, "%Y-%m-%dT%H:%M:%SZ") + ts = dt.datetime.strptime(ts, "%Y-%m-%dT%H:%M:%SZ") # type: Timestamp if python_version >= (3,0): ts = ts.replace(tzinfo=dt.timezone.utc) diff --git a/src/osmium/replication/utils.pyi b/src/osmium/replication/utils.pyi deleted file mode 100644 index 57022218..00000000 --- a/src/osmium/replication/utils.pyi +++ /dev/null @@ -1,15 +0,0 @@ -import logging -from datetime import datetime - -import typing - -log: logging.Logger - -Sequence = typing.NewType('Sequence', int) -Timestamp = typing.NewType('Timestamp', datetime) - -ReplicationHeader = typing.NamedTuple('ReplicationHeader', - [('url', str), ('sequence', Sequence), ('timestamp', Timestamp)]) - - -def get_replication_header(fname: str) -> ReplicationHeader: ... diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 00000000..d1bcee5e --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,2 @@ +nose + From 0331337ecccbc64e0efdd6c433ce9059fa25772a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Sun, 3 Feb 2019 13:11:04 +0100 Subject: [PATCH 07/16] Add pyi files to build --- setup.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/setup.py b/setup.py index 52042460..8b74535f 100644 --- a/setup.py +++ b/setup.py @@ -2,12 +2,17 @@ import re import sys import platform +import shutil import subprocess +import tempfile from setuptools import setup, Extension from setuptools.command.build_ext import build_ext from setuptools.command.sdist import sdist as orig_sdist +from setuptools.command.build_py import build_py from distutils.version import LooseVersion +from sys import executable, version_info as python_version + BASEDIR = os.path.split(os.path.abspath(__file__))[0] @@ -66,6 +71,8 @@ def run(self): for ext in self.extensions: self.build_extension(ext) + self.generate_pyi() + def build_extension(self, ext): extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, @@ -110,11 +117,65 @@ def build_extension(self, ext): subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp, env=env) subprocess.check_call(['cmake', '--build', '.'] + build_args, cwd=self.build_temp) + def generate_pyi(self): + # set python executable + if python_version >= (3, 4, 0): + python_name = executable + else: + if platform == 'win32': + python_name = 'py -3' + else: + python_name = 'python3' + + # set target directory + dst = self.build_lib + # test that everything is OK + env = os.environ.copy() + env['PYTHONPATH'] = dst + + # test if there is no errors in osmium, stubgen doesn't report error on import error + import_test = subprocess.Popen([python_name, '-c', 'import osmium'], env=env, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + if import_test.wait(): + error = "" + if import_test.stdout: + error += "\n".join(x.decode('utf-8') for x in import_test.stdout.readlines()) + if import_test.stderr: + error += "\n".join(x.decode('utf-8') for x in import_test.stderr.readlines()) + raise Exception("Failure importing osmium: \n" + error) + + # generate pyi files + with tempfile.TemporaryDirectory() as tmpdir: + p = subprocess.Popen([python_name, '-m', 'mypy.stubgen', '-p', 'osmium', '-o', tmpdir], env=env, + stderr=subprocess.PIPE, stdout=subprocess.PIPE) + retcode = p.wait() + error = "" + if p.stdout: + error += "\n".join(x.decode('utf-8') for x in p.stdout.readlines()) + if p.stderr: + error += "\n".join(x.decode('utf-8') for x in p.stderr.readlines()) + if retcode: + raise Exception("Failure calling stubgen: \n" + error) + for pyi in (os.path.join("osmium", "osm", "_osm.pyi"), + os.path.join("osmium", "replication", "_replication.pyi"), + os.path.join("osmium", '_osmium.pyi'), + os.path.join("osmium", 'geom.pyi'), + os.path.join("osmium", 'index.pyi'), + os.path.join("osmium", 'io.pyi')): + shutil.copyfile(os.path.join(tmpdir, pyi), os.path.join(dst, pyi)) + versions = get_versions() with open('README.rst', 'r') as descfile: long_description = descfile.read() +base_data_files_folder = os.path.join("lib", "python{}.{}".format(*sys.version_info[:2]), "site-packages", "osmium") + + +def path_join_list(path_prefix, lst): + return [os.path.join(path_prefix, p) for p in lst] + + setup( name='osmium', version=versions['pyosmium_release'], From b5f4c6ba972749065587d702b2bc2a1a2a1564b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Sun, 3 Feb 2019 15:18:27 +0100 Subject: [PATCH 08/16] Add imports so docstring contains references to python objects, not C++ --- lib/io.cc | 1 + lib/osmium.cc | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/io.cc b/lib/io.cc index a9c0c439..c1926da2 100644 --- a/lib/io.cc +++ b/lib/io.cc @@ -7,6 +7,7 @@ namespace py = pybind11; PYBIND11_MODULE(io, m) { + py::module::import("osmium.osm"); // needed to get proper type for osmium::io::Header::box py::class_(m, "Header", "File header with global information about the file.") .def(py::init<>()) diff --git a/lib/osmium.cc b/lib/osmium.cc index 7f1a29ff..4e0399a0 100644 --- a/lib/osmium.cc +++ b/lib/osmium.cc @@ -25,6 +25,8 @@ PYBIND11_MODULE(_osmium, m) { } }); + py::module::import("osmium.io"); // needed to get proper type for osmium::io::Reader + m.def("apply", [](osmium::io::Reader &rd, BaseHandler &h) { osmium::apply(rd, h); }, py::arg("reader"), py::arg("handler"), From 5d10571d726d7acf67fa20a166ed7a3645827f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Sun, 3 Feb 2019 15:39:06 +0100 Subject: [PATCH 09/16] Use build-requirements.txt and test-requirements.txt in travis.yml --- .travis.yml | 8 ++------ test-requirements.txt | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 22c8e910..27cbb74b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,20 +43,16 @@ addons: packages: - libboost1.58-dev - python-dev - - python-nose - - python-mock - python3 - python3-dev - - python3-nose - python3-setuptools install: - git clone --quiet --depth 1 https://github.com/osmcode/libosmium.git contrib/libosmium - git clone --quiet --depth 1 https://github.com/mapbox/protozero.git contrib/protozero - git clone --quiet --depth 1 https://github.com/pybind/pybind11.git contrib/pybind11 - - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then - pip${USE_PYTHON_VERSION} install -q nose mock; - fi + - pip${USE_PYTHON_VERSION} install -q -r build-requirements.txt + - pip${USE_PYTHON_VERSION} install -q -r test-requirements.txt script: - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then diff --git a/test-requirements.txt b/test-requirements.txt index d1bcee5e..a6786964 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,2 +1,2 @@ nose - +mock From fa677cd361e0f90464dd787bb7d0df84f25e4e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Sun, 3 Feb 2019 16:21:34 +0100 Subject: [PATCH 10/16] Remove unused functions/variables --- setup.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/setup.py b/setup.py index 8b74535f..96195ffc 100644 --- a/setup.py +++ b/setup.py @@ -169,12 +169,6 @@ def generate_pyi(self): with open('README.rst', 'r') as descfile: long_description = descfile.read() -base_data_files_folder = os.path.join("lib", "python{}.{}".format(*sys.version_info[:2]), "site-packages", "osmium") - - -def path_join_list(path_prefix, lst): - return [os.path.join(path_prefix, p) for p in lst] - setup( name='osmium', From f4c2818c702bc375f4b4f8893ca80a212d425068 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Sun, 3 Feb 2019 16:22:48 +0100 Subject: [PATCH 11/16] Remove unncesessary pyi files --- src/osmium/_osmium.pyi | 75 --------- src/osmium/geom.pyi | 66 -------- src/osmium/index.pyi | 19 --- src/osmium/io.pyi | 39 ----- src/osmium/osm/_osm.pyi | 207 ------------------------ src/osmium/replication/_replication.pyi | 4 - 6 files changed, 410 deletions(-) delete mode 100644 src/osmium/_osmium.pyi delete mode 100644 src/osmium/geom.pyi delete mode 100644 src/osmium/index.pyi delete mode 100644 src/osmium/io.pyi delete mode 100644 src/osmium/osm/_osm.pyi delete mode 100644 src/osmium/replication/_replication.pyi diff --git a/src/osmium/_osmium.pyi b/src/osmium/_osmium.pyi deleted file mode 100644 index 9ccb9c19..00000000 --- a/src/osmium/_osmium.pyi +++ /dev/null @@ -1,75 +0,0 @@ -import typing - -from .io import Reader, Writer -from .osm import Location, Node, Way, Relation, Area, Changeset, mutable - - -class InvalidLocationError(RuntimeError): ... - - -class NotFoundError(KeyError): ... - - -class MergeInputReader(Reader): - def add_buffer(self, buffer, format: str) -> int: ... - - def add_file(self, file: str) -> int: ... - - def apply(self, handler: BaseHandler, idx: typing.Optional[str], simplify: bool = ...): ... - - def apply_to_reader(self, reader: Reader, writer: Writer, with_history: bool = ...): ... - - -LocationTable = typing.Mapping[int, Location] - - -class NodeLocationsForWays(LocationTable): - def ignore_errors(self): ... - - -class BaseHandler: - def node(self, node: Node): ... - - def way(self, way: Way): ... - - def relation(self, relation: Relation): ... - - def area(self, area: Area): ... - - def changeset(self, changeset: Changeset): ... - - def apply_start(self): ... - - -class SimpleHandler(BaseHandler): - def apply_buffer(self, buffer: bytes, format: str, locations: bool = ..., idx: str = ...): ... - - def apply_file(self, filename: str, locations: bool = ..., idx: str = ...): ... - - -class SimpleWriter: - def __init__(self, arg2: str, arg3: typing.Optional[int]): ... # filename, buffer_size - - def add_node(self, node: typing.Union[Node, mutable.Node]): ... - - def add_relation(self, relation: typing.Union[Relation, mutable.Relation]): ... - - def add_way(self, way: typing.Union[Way, mutable.Way]): ... - - def close(self): ... - - -class WriteHandler(BaseHandler): - def __init__(self, arg2: str, arg3: typing.Optional[int]): ... # filename, buffer_size - - -@typing.overload -def apply(arg1: Reader, arg2: BaseHandler): ... # reader, write_handler - - -@typing.overload -def apply(arg1: Reader, arg2: NodeLocationsForWays): ... # reader, nodes_idx - - -@typing.overload -def apply(arg1: Reader, arg2: NodeLocationsForWays, arg3: BaseHandler): ... # reader, nodes_idx, write_handler diff --git a/src/osmium/geom.pyi b/src/osmium/geom.pyi deleted file mode 100644 index 92d1c0f2..00000000 --- a/src/osmium/geom.pyi +++ /dev/null @@ -1,66 +0,0 @@ -import typing - -from .osm import WayNodeList, Area, Location, Node, NodeRef - - -class BaseFactory: - epsg: int - proj_string: str - - def create_linestring(self, list: WayNodeList, use_nodes: use_nodes, direction: direction) -> str: ... - - def create_multipolygon(self, area: Area) -> str: ... - - @typing.overload - def create_point(self, location: Location) -> str: ... - - @typing.overload - def create_point(self, node: Node) -> str: ... - - @typing.overload - def create_point(self, ref: NodeRef) -> str: ... - - -class GeoJSONFactory(BaseFactory): ... - - -class WKBFactory(BaseFactory): ... - - -class WKTFactory(BaseFactory): ... - - -def haversine_distance(list: WayNodeList) -> float: ... - - -def lonlat_to_mercator(coordinates: Coordinates) -> float: ... - - -def mercator_to_lonlat(coordinates: Coordinates) -> float: ... - - -class Coordinates: - x: float - y: float - - @typing.overload - def __init__(self, lon: float, lat: float): ... - - @typing.overload - def __init__(self, location: Location): ... - - def valid(self) -> bool: ... - - -class direction: - BACKWARD: direction = ... - FORWARD: direction = ... - names: typing.Dict[str, direction] = ... - values: typing.Dict[int, direction] = ... - - -class use_nodes: - ALL: use_nodes = ... - UNIQUE: use_nodes = ... - names: typing.Dict[str, use_nodes] = ... - values: typing.Dict[int, use_nodes] = ... diff --git a/src/osmium/index.pyi b/src/osmium/index.pyi deleted file mode 100644 index 60dfd3e2..00000000 --- a/src/osmium/index.pyi +++ /dev/null @@ -1,19 +0,0 @@ -import typing - -from .osm import Location - - -class LocationTable: - def clear(self): ... - - def get(self, id: int) -> Location: ... - - def set(self, id: int, loc: Location): ... - - def used_memory(self) -> int: ... - - -def create_map(map_type: str) -> LocationTable: ... - - -def map_types() -> typing.List[str]: ... diff --git a/src/osmium/io.pyi b/src/osmium/io.pyi deleted file mode 100644 index 1cb46ada..00000000 --- a/src/osmium/io.pyi +++ /dev/null @@ -1,39 +0,0 @@ -import typing - -from .osm import Box - -osm_entity_bits = typing.NewType(int) - - -class Header: - has_multiple_object_versions: bool - - def box(self) -> Box: ... - - def get(self, key: str, default: typing.Optional[str]) -> str: ... - - def set(self, key: str, value: str): ... - - -class Reader: - @typing.overload - def __init__(self, arg2: str): ... - - @typing.overload - def __init__(self, arg2: str, arg3: osm_entity_bits): ... - - def close(self): ... - - def eof(self) -> bool: ... - - def header(self) -> Header: ... - - -class Writer: - @typing.overload - def __init__(self, arg2: str): ... - - @typing.overload - def __init__(self, arg2: str, arg3: Header): ... - - def close(self): ... diff --git a/src/osmium/osm/_osm.pyi b/src/osmium/osm/_osm.pyi deleted file mode 100644 index b418f11d..00000000 --- a/src/osmium/osm/_osm.pyi +++ /dev/null @@ -1,207 +0,0 @@ -import datetime - -import typing - -from osmium.osm import mutable -from osmium.replication.utils import Timestamp - -OSMObjectIdType = typing.NewType('OSMObjectId', int) -UnsginedOSMObjectIdType = typing.NewType('UnsginedOSMObjectIdType', OSMObjectIdType) -UidType = typing.NewType('UserId', int) -VersionType = typing.NewType('VersionType', int) - - -class OSMObject: - id: OSMObjectIdType - deleted: bool - visible: bool - version: VersionType - changeset: ChangesetId - uid: UidType - timestamp: Timestamp - user: str - tags: TagList - - def positive_id(self) -> UnsginedOSMObjectIdType: ... - - def user_is_anonymous(self) -> bool: ... - - -class NodeRefList: - def __len__(self) -> int: ... - - def __getitem__(self, arg2: int) -> NodeRef: ... - - def __iter__(self) -> typing.Iterable[NodeRef]: ... - - def ends_have_same_id(self) -> bool: ... - - def ends_have_same_location(self) -> bool: ... - - def is_closed(self) -> bool: ... - - -class InnerRing(NodeRefList): ... - - -InnerRingIterator = typing.Iterable[InnerRing] - - -class OuterRing(NodeRefList): ... - - -OuterRingIterator = typing.Iterable[OuterRing] - - -class Area(OSMObject): - def from_way(self) -> bool: ... - - def orig_id(self) -> OSMObjectIdType: ... - - def is_multipolygon(self) -> bool: ... - - def num_rings(self) -> typing.Tuple[int, int]: ... - - def outer_rings(self) -> OuterRingIterator: ... - - def inner_rings(self) -> InnerRingIterator: ... - - -class Box: - bottom_left: Location - top_right: Location - - @typing.overload - def __init__(self): ... - - @typing.overload - def __init__(self, arg2: float, arg3: float, arg4: float, arg5: float): ... - - @typing.overload - def __init__(self, arg2: Location, arg3: Location): ... - - def contains(self, location: Location) -> bool: ... - - @typing.overload - def extend(self, arg2: Location) -> Box: ... - - @typing.overload - def extend(self, arg2: Box) -> Box: ... - - def size(self) -> float: ... - - def valid(self) -> bool: ... - - -ChangesetId = typing.NewType('ChangesetId', int) - - -class Changeset: - id: ChangesetId - uid: UidType - created_at: datetime.datetime # ??? - closed_at: datetime.datetime # ??? - open: bool - num_changes: int - bounds: Box - user: str - tags: TagList - - def user_is_anonymous(self) -> bool: ... - - -class Location: - lat: float - lon: float - x: float - y: float - - def __init__(self, arg2: float, arg3: float): ... # x, y ? - - def lat_without_check(self) -> float: ... - - def lon_without_check(self) -> float: ... - - def valid(self) -> bool: ... - - -class Node(OSMObject): - location: Location - - def replace(self) -> mutable.Node: ... - - -class NodeRef: - ref: OSMObjectIdType - location: Location - lat: float - lon: float - x: float - y: float - - -class Relation(OSMObject): - members: RelationMemberList - - def replace(self) -> mutable.Relation: ... - - -class RelationMember: - ref: OSMObjectIdType - type: str - role: str - - -class RelationMemberList: - def __len__(self) -> int: ... - - def __iter__(self) -> typing.Iterable[RelationMember]: ... - - -class Tag: - k: str - v: str - - -class TagList: - def __len__(self) -> int: ... - - def __getitem__(self, arg2: str) -> str: ... - - def __contains__(self, arg2: str) -> bool: ... - - def __iter__(self) -> typing.Iterable[Tag]: ... # ??? - - @typing.overload - def get(self, arg2) -> str: ... - - @typing.overload - def get(self, key: str, default: str) -> str: ... - - -class Way(OSMObject): - nodes: WayNodeList - - def ends_have_same_id(self) -> bool: ... - - def ends_have_same_location(self) -> bool: ... - - def is_closed(self) -> bool: ... - - def replace(self) -> mutable.Way: ... - - -class WayNodeList(NodeRefList): ... - - -class osm_entity_bits: - ALL: osm_entity_bits = ... - AREA: osm_entity_bits = ... - CHANGESET: osm_entity_bits = ... - NODE: osm_entity_bits = ... - NOTHING: osm_entity_bits = ... - OBJECT: osm_entity_bits = ... - RELATION: osm_entity_bits = ... - WAY: osm_entity_bits = ... - names: typing.Dict[str, osm_entity_bits] = ... - values: typing.Dict[int, osm_entity_bits] = ... diff --git a/src/osmium/replication/_replication.pyi b/src/osmium/replication/_replication.pyi deleted file mode 100644 index e24b778d..00000000 --- a/src/osmium/replication/_replication.pyi +++ /dev/null @@ -1,4 +0,0 @@ -from ..replication.utils import Timestamp - - -def newest_change_from_file(arg1: str) -> Timestamp: ... From 229bb99ebb1a3901def974a805968308cab5a88d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Sun, 3 Feb 2019 16:25:55 +0100 Subject: [PATCH 12/16] Use build-requirements.txt and test-requirements.txt --- .travis.yml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 27cbb74b..068e3ec9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,17 +51,15 @@ install: - git clone --quiet --depth 1 https://github.com/osmcode/libosmium.git contrib/libosmium - git clone --quiet --depth 1 https://github.com/mapbox/protozero.git contrib/protozero - git clone --quiet --depth 1 https://github.com/pybind/pybind11.git contrib/pybind11 - - pip${USE_PYTHON_VERSION} install -q -r build-requirements.txt - - pip${USE_PYTHON_VERSION} install -q -r test-requirements.txt + - if [[ $TRAVIS_OS_NAME == 'osx' ]]; then pip${USE_PYTHON_VERSION} install -U virtualenv ; fi + - virtualenv -p python${USE_PYTHON_VERSION} build_env + - virtualenv -p python${USE_PYTHON_VERSION} test_env + - build_env/bin/pip install -q -r build-requirements.txt + - test_env/bin/pip install -q -r test-requirements.txt script: - - if [ "$TRAVIS_OS_NAME" = 'osx' ]; then - PYTHON=python${USE_PYTHON_VERSION}; - else - PYTHON=/usr/bin/python${USE_PYTHON_VERSION}; - fi - - $PYTHON --version - - $PYTHON setup.py build + - build_env/bin/python --version + - build_env/bin/python setup.py build - cd test - - $PYTHON run_tests.py + - ../test_env/bin/python run_tests.py From 69b07123e62de5a3efcea77114016fec9f99f7d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Sun, 3 Feb 2019 16:37:01 +0100 Subject: [PATCH 13/16] Use mypy only for python3 --- build-requirements.txt | 2 +- setup.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/build-requirements.txt b/build-requirements.txt index f0aa93ac..cbd771a7 100644 --- a/build-requirements.txt +++ b/build-requirements.txt @@ -1 +1 @@ -mypy +mypy; python_version > '3.0 diff --git a/setup.py b/setup.py index 96195ffc..ac888852 100644 --- a/setup.py +++ b/setup.py @@ -127,6 +127,9 @@ def generate_pyi(self): else: python_name = 'python3' + if python_version[0] < 3: + return # no mypy for python2 + # set target directory dst = self.build_lib # test that everything is OK From 9c4bcd350d873f39c9724c55f395afc9e7220ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Sun, 3 Feb 2019 18:04:09 +0100 Subject: [PATCH 14/16] fix spec --- build-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-requirements.txt b/build-requirements.txt index cbd771a7..32cff01d 100644 --- a/build-requirements.txt +++ b/build-requirements.txt @@ -1 +1 @@ -mypy; python_version > '3.0 +mypy; python_version > '3.0' From c7a3cdc758d370144e5eb8c0a17c97b9b69f1ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Sat, 9 Feb 2019 22:12:09 +0100 Subject: [PATCH 15/16] Add information about typing to pip package, fix types --- build-requirements.txt | 2 +- setup.py | 1 + src/osmium/osm/__init__.py | 2 +- src/osmium/osm/mutable.py | 31 +++++++++++++++---------------- src/osmium/py.typed | 0 src/osmium/replication/server.py | 5 +++-- 6 files changed, 21 insertions(+), 20 deletions(-) create mode 100644 src/osmium/py.typed diff --git a/build-requirements.txt b/build-requirements.txt index 32cff01d..67c63e59 100644 --- a/build-requirements.txt +++ b/build-requirements.txt @@ -1 +1 @@ -mypy; python_version > '3.0' +mypy>=0.680; python_version > '3.0' diff --git a/setup.py b/setup.py index ac888852..b2a525f8 100644 --- a/setup.py +++ b/setup.py @@ -204,6 +204,7 @@ def generate_pyi(self): ext_modules=[CMakeExtension('cmake_example')], packages = ['osmium', 'osmium/osm', 'osmium/replication'], package_dir = {'' : 'src'}, + package_data={'osmium': ['py.typed']}, cmdclass=dict(build_ext=CMakeBuild, sdist=Pyosmium_sdist), zip_safe=False, ) diff --git a/src/osmium/osm/__init__.py b/src/osmium/osm/__init__.py index 77ca2400..fff66020 100644 --- a/src/osmium/osm/__init__.py +++ b/src/osmium/osm/__init__.py @@ -1,5 +1,5 @@ -from ._osm import * import osmium.osm.mutable +from osmium.osm._osm import * MYPY = False if MYPY: diff --git a/src/osmium/osm/mutable.py b/src/osmium/osm/mutable.py index 79a2c6ce..99f87755 100644 --- a/src/osmium/osm/mutable.py +++ b/src/osmium/osm/mutable.py @@ -2,15 +2,14 @@ if MYPY: import typing from typing import Optional - from . import TagList + from ._osm import TagList, Location from ..replication.utils import Timestamp - from . import Location - from .. import osm + from . import _osm as osm - OSMObjectIdType = typing.NewType('OSMObjectId', int) + OSMObjectIdType = typing.NewType('OSMObjectIdType', int) VersionType = typing.NewType('VersionType', int) UnsginedOSMObjectIdType = typing.NewType('UnsginedOSMObjectIdType', OSMObjectIdType) - UidType = typing.NewType('UserId', int) + UidType = typing.NewType('UidType', int) ChangesetId = typing.NewType('ChangesetId', int) LocationType = typing.Union[Location, typing.Tuple[float, float]] @@ -35,15 +34,15 @@ class OSMObject(object): def __init__(self, base=None, id=None, version=None, visible=None, changeset=None, timestamp=None, uid=None, tags=None): - # type: (Optional[typing.Any], Optional[OSMObjectIdType], Optional[VersionType], bool, ChangesetId, Timestamp, UidType, typing.Union[TagList, typing.Dict[str, str]]) -> None + # type: (Optional[typing.Any], Optional[OSMObjectIdType], Optional[VersionType], Optional[bool], Optional[ChangesetId], Optional[Timestamp], Optional[UidType], Optional[typing.Union[TagList, typing.Dict[str, str]]]) -> None if base is None: - self.id = id # type: OSMObjectIdType - self.version = version # type: VersionType - self.visible = visible # type: bool - self.changeset = changeset # type: ChangesetId - self.timestamp = timestamp # type: Timestamp - self.uid = uid # type: UidType - self.tags = tags # typing.Union[TagList, typing.Dict[str, str]] + self.id = id # type: Optional[OSMObjectIdType] + self.version = version # type: Optional[VersionType] + self.visible = visible # type: Optional[bool] + self.changeset = changeset # type: Optional[ChangesetId] + self.timestamp = timestamp # type: Optional[Timestamp] + self.uid = uid # type: Optional[UidType] + self.tags = tags # type: Optional[typing.Union[TagList, typing.Dict[str, str]]] else: self.id = base.id if id is None else id self.version = base.version if version is None else version @@ -64,7 +63,7 @@ def __init__(self, base=None, location=None, **attrs): # type: (Optional[osm.Node], Optional[LocationType], typing.Any) -> None OSMObject.__init__(self, base=base, **attrs) if base is None: - self.location = location # type: LocationType + self.location = location # type: Optional[LocationType] else: self.location = location if location is not None else base.location @@ -82,7 +81,7 @@ def __init__(self, base=None, nodes=None, **attrs): # type: (Optional[osm.Way], Optional[NodeListType], typing.Any) -> None OSMObject.__init__(self, base=base, **attrs) if base is None: - self.nodes = nodes # type: NodeListType + self.nodes = nodes # type: Optional[NodeListType] else: self.nodes = nodes if nodes is not None else base.nodes @@ -99,7 +98,7 @@ def __init__(self, base=None, members=None, **attrs): # type: (Optional[osm.Relation], Optional[RelationMembersType], typing.Any) -> None OSMObject.__init__(self, base=base, **attrs) if base is None: - self.members = members # type: RelationMembersType + self.members = members # type: Optional[RelationMembersType] else: self.members = members if members is not None else base.members diff --git a/src/osmium/py.typed b/src/osmium/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/src/osmium/replication/server.py b/src/osmium/replication/server.py index d30cbd06..9ca626f5 100644 --- a/src/osmium/replication/server.py +++ b/src/osmium/replication/server.py @@ -98,7 +98,7 @@ def collect_diffs(self, start_id, max_size=1024): try: diffdata = self.get_diff_block(current_id) except: - diffdata = '' + diffdata = b'' if len(diffdata) == 0: if start_id == current_id: return None @@ -184,6 +184,7 @@ def apply_diffs_to_file(self, infile, outfile, start_id, max_size=1024, h.set("osmosis_replication_base_url", self.baseurl) h.set("osmosis_replication_sequence_number", str(diffs.id)) info = self.get_state_info(diffs.id) + # TODO: what if info is None? h.set("osmosis_replication_timestamp", info.timestamp.strftime("%Y-%m-%dT%H:%M:%SZ")) for k,v in extra_headers.items(): h.set(k, v) @@ -328,7 +329,7 @@ def get_diff_block(self, seq): def get_state_url(self, seq): - # type: (Sequence) -> str + # type: (typing.Optional[Sequence]) -> str """ Returns the URL of the state.txt files for a given sequence id. If seq is `None` the URL for the latest state info is returned, From 2c80fb255aaf77436c730b9f404682c961e50cb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Niesiob=C4=99dzki?= Date: Sat, 9 Feb 2019 22:20:03 +0100 Subject: [PATCH 16/16] fix mypy version --- build-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-requirements.txt b/build-requirements.txt index 67c63e59..a3bc62a8 100644 --- a/build-requirements.txt +++ b/build-requirements.txt @@ -1 +1 @@ -mypy>=0.680; python_version > '3.0' +mypy>=0.670; python_version > '3.0'