From 57384ce0338e32763f148e3f493f78631c9b0740 Mon Sep 17 00:00:00 2001 From: Vasily Zakharov Date: Thu, 10 Oct 2019 05:28:42 +0300 Subject: [PATCH] Revised stubs for geoip2 third party library (#3317) --- stdlib/3/ipaddress.pyi | 20 +-- tests/check_consistent.py | 1 + third_party/2/ipaddress.pyi | 149 ++++++++++++++++++ third_party/2and3/geoip2/__init__.pyi | 0 third_party/2and3/geoip2/database.pyi | 22 +++ third_party/2and3/geoip2/errors.pyi | 18 +++ third_party/2and3/geoip2/mixins.pyi | 3 + third_party/2and3/geoip2/models.pyi | 65 ++++++++ third_party/2and3/geoip2/records.pyi | 83 ++++++++++ third_party/2and3/maxminddb/__init__.pyi | 7 + third_party/{3 => 2and3}/maxminddb/compat.pyi | 2 - third_party/{3 => 2and3}/maxminddb/const.pyi | 2 - .../{3 => 2and3}/maxminddb/decoder.pyi | 2 - third_party/{3 => 2and3}/maxminddb/errors.pyi | 2 - .../{3 => 2and3}/maxminddb/extension.pyi | 10 +- third_party/{3 => 2and3}/maxminddb/reader.pyi | 14 +- third_party/3/maxminddb/__init__.pyi | 9 -- 17 files changed, 368 insertions(+), 41 deletions(-) create mode 100644 third_party/2/ipaddress.pyi create mode 100644 third_party/2and3/geoip2/__init__.pyi create mode 100644 third_party/2and3/geoip2/database.pyi create mode 100644 third_party/2and3/geoip2/errors.pyi create mode 100644 third_party/2and3/geoip2/mixins.pyi create mode 100644 third_party/2and3/geoip2/models.pyi create mode 100644 third_party/2and3/geoip2/records.pyi create mode 100644 third_party/2and3/maxminddb/__init__.pyi rename third_party/{3 => 2and3}/maxminddb/compat.pyi (85%) rename third_party/{3 => 2and3}/maxminddb/const.pyi (76%) rename third_party/{3 => 2and3}/maxminddb/decoder.pyi (83%) rename third_party/{3 => 2and3}/maxminddb/errors.pyi (52%) rename third_party/{3 => 2and3}/maxminddb/extension.pyi (80%) rename third_party/{3 => 2and3}/maxminddb/reader.pyi (66%) delete mode 100644 third_party/3/maxminddb/__init__.pyi diff --git a/stdlib/3/ipaddress.pyi b/stdlib/3/ipaddress.pyi index 3d507f41b..6b6a45d1d 100644 --- a/stdlib/3/ipaddress.pyi +++ b/stdlib/3/ipaddress.pyi @@ -1,5 +1,5 @@ from typing import (Any, Container, Generic, Iterable, Iterator, Optional, - overload, SupportsInt, Tuple, TypeVar) + overload, SupportsInt, Text, Tuple, TypeVar) # Undocumented length constants IPV4LENGTH: int @@ -21,11 +21,11 @@ class _IPAddressBase: def __lt__(self: _T, other: _T) -> bool: ... def __ne__(self, other: Any) -> bool: ... @property - def compressed(self) -> str: ... + def compressed(self) -> Text: ... @property - def exploded(self) -> str: ... + def exploded(self) -> Text: ... @property - def reverse_pointer(self) -> str: ... + def reverse_pointer(self) -> Text: ... @property def version(self) -> int: ... @@ -90,11 +90,11 @@ class _BaseNetwork(_IPAddressBase, Container[_A], Iterable[_A], Generic[_A]): def subnets(self: _T, prefixlen_diff: int = ..., new_prefix: Optional[int] = ...) -> Iterator[_T]: ... def supernet(self: _T, prefixlen_diff: int = ..., new_prefix: Optional[int] = ...) -> _T: ... @property - def with_hostmask(self) -> str: ... + def with_hostmask(self) -> Text: ... @property - def with_netmask(self) -> str: ... + def with_netmask(self) -> Text: ... @property - def with_prefixlen(self) -> str: ... + def with_prefixlen(self) -> Text: ... @property def hostmask(self) -> _A: ... @@ -105,11 +105,11 @@ class _BaseInterface(_BaseAddress, Generic[_A, _N]): @property def ip(self) -> _A: ... @property - def with_hostmask(self) -> str: ... + def with_hostmask(self) -> Text: ... @property - def with_netmask(self) -> str: ... + def with_netmask(self) -> Text: ... @property - def with_prefixlen(self) -> str: ... + def with_prefixlen(self) -> Text: ... class IPv4Address(_BaseAddress): ... class IPv4Network(_BaseNetwork[IPv4Address]): ... diff --git a/tests/check_consistent.py b/tests/check_consistent.py index 161cea2d8..afe81869b 100755 --- a/tests/check_consistent.py +++ b/tests/check_consistent.py @@ -26,6 +26,7 @@ consistent_files = [ {'stdlib/3.7/dataclasses.pyi', 'third_party/3/dataclasses.pyi'}, {'stdlib/3/pathlib.pyi', 'third_party/2/pathlib2.pyi'}, {'stdlib/3.7/contextvars.pyi', 'third_party/3/contextvars.pyi'}, + {'stdlib/3/ipaddress.pyi', 'third_party/2/ipaddress.pyi'}, ] def main(): diff --git a/third_party/2/ipaddress.pyi b/third_party/2/ipaddress.pyi new file mode 100644 index 000000000..6b6a45d1d --- /dev/null +++ b/third_party/2/ipaddress.pyi @@ -0,0 +1,149 @@ +from typing import (Any, Container, Generic, Iterable, Iterator, Optional, + overload, SupportsInt, Text, Tuple, TypeVar) + +# Undocumented length constants +IPV4LENGTH: int +IPV6LENGTH: int + +_A = TypeVar("_A", IPv4Address, IPv6Address) +_N = TypeVar("_N", IPv4Network, IPv6Network) +_T = TypeVar("_T") + +def ip_address(address: object) -> Any: ... # morally Union[IPv4Address, IPv6Address] +def ip_network(address: object, strict: bool = ...) -> Any: ... # morally Union[IPv4Network, IPv6Network] +def ip_interface(address: object) -> Any: ... # morally Union[IPv4Interface, IPv6Interface] + +class _IPAddressBase: + def __eq__(self, other: Any) -> bool: ... + def __ge__(self: _T, other: _T) -> bool: ... + def __gt__(self: _T, other: _T) -> bool: ... + def __le__(self: _T, other: _T) -> bool: ... + def __lt__(self: _T, other: _T) -> bool: ... + def __ne__(self, other: Any) -> bool: ... + @property + def compressed(self) -> Text: ... + @property + def exploded(self) -> Text: ... + @property + def reverse_pointer(self) -> Text: ... + @property + def version(self) -> int: ... + +class _BaseAddress(_IPAddressBase, SupportsInt): + def __init__(self, address: object) -> None: ... + def __add__(self: _T, other: int) -> _T: ... + def __hash__(self) -> int: ... + def __int__(self) -> int: ... + def __sub__(self: _T, other: int) -> _T: ... + @property + def is_global(self) -> bool: ... + @property + def is_link_local(self) -> bool: ... + @property + def is_loopback(self) -> bool: ... + @property + def is_multicast(self) -> bool: ... + @property + def is_private(self) -> bool: ... + @property + def is_reserved(self) -> bool: ... + @property + def is_unspecified(self) -> bool: ... + @property + def max_prefixlen(self) -> int: ... + @property + def packed(self) -> bytes: ... + +class _BaseNetwork(_IPAddressBase, Container[_A], Iterable[_A], Generic[_A]): + network_address: _A + netmask: _A + def __init__(self, address: object, strict: bool = ...) -> None: ... + def __contains__(self, other: Any) -> bool: ... + def __getitem__(self, n: int) -> _A: ... + def __iter__(self) -> Iterator[_A]: ... + def address_exclude(self: _T, other: _T) -> Iterator[_T]: ... + @property + def broadcast_address(self) -> _A: ... + def compare_networks(self: _T, other: _T) -> int: ... + def hosts(self) -> Iterator[_A]: ... + @property + def is_global(self) -> bool: ... + @property + def is_link_local(self) -> bool: ... + @property + def is_loopback(self) -> bool: ... + @property + def is_multicast(self) -> bool: ... + @property + def is_private(self) -> bool: ... + @property + def is_reserved(self) -> bool: ... + @property + def is_unspecified(self) -> bool: ... + @property + def max_prefixlen(self) -> int: ... + @property + def num_addresses(self) -> int: ... + def overlaps(self: _T, other: _T) -> bool: ... + @property + def prefixlen(self) -> int: ... + def subnets(self: _T, prefixlen_diff: int = ..., new_prefix: Optional[int] = ...) -> Iterator[_T]: ... + def supernet(self: _T, prefixlen_diff: int = ..., new_prefix: Optional[int] = ...) -> _T: ... + @property + def with_hostmask(self) -> Text: ... + @property + def with_netmask(self) -> Text: ... + @property + def with_prefixlen(self) -> Text: ... + @property + def hostmask(self) -> _A: ... + +class _BaseInterface(_BaseAddress, Generic[_A, _N]): + hostmask: _A + netmask: _A + network: _N + @property + def ip(self) -> _A: ... + @property + def with_hostmask(self) -> Text: ... + @property + def with_netmask(self) -> Text: ... + @property + def with_prefixlen(self) -> Text: ... + +class IPv4Address(_BaseAddress): ... +class IPv4Network(_BaseNetwork[IPv4Address]): ... +class IPv4Interface(IPv4Address, _BaseInterface[IPv4Address, IPv4Network]): ... + +class IPv6Address(_BaseAddress): + @property + def ipv4_mapped(self) -> Optional[IPv4Address]: ... + @property + def is_site_local(self) -> bool: ... + @property + def sixtofour(self) -> Optional[IPv4Address]: ... + @property + def teredo(self) -> Optional[Tuple[IPv4Address, IPv4Address]]: ... + +class IPv6Network(_BaseNetwork[IPv6Address]): + @property + def is_site_local(self) -> bool: ... + +class IPv6Interface(IPv6Address, _BaseInterface[IPv6Address, IPv6Network]): ... + +def v4_int_to_packed(address: int) -> bytes: ... +def v6_int_to_packed(address: int) -> bytes: ... +@overload +def summarize_address_range(first: IPv4Address, last: IPv4Address) -> Iterator[IPv4Network]: ... +@overload +def summarize_address_range(first: IPv6Address, last: IPv6Address) -> Iterator[IPv6Network]: ... +def collapse_addresses(addresses: Iterable[_N]) -> Iterator[_N]: ... +@overload +def get_mixed_type_key(obj: _A) -> Tuple[int, _A]: ... +@overload +def get_mixed_type_key(obj: IPv4Network) -> Tuple[int, IPv4Address, IPv4Address]: ... +@overload +def get_mixed_type_key(obj: IPv6Network) -> Tuple[int, IPv6Address, IPv6Address]: ... + +class AddressValueError(ValueError): ... +class NetmaskValueError(ValueError): ... diff --git a/third_party/2and3/geoip2/__init__.pyi b/third_party/2and3/geoip2/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/2and3/geoip2/database.pyi b/third_party/2and3/geoip2/database.pyi new file mode 100644 index 000000000..7a8991160 --- /dev/null +++ b/third_party/2and3/geoip2/database.pyi @@ -0,0 +1,22 @@ +from types import TracebackType +from typing import Optional, Sequence, Text, Type + +from maxminddb.reader import Metadata +from geoip2.models import AnonymousIP, ASN, City, ConnectionType, Country, Domain, Enterprise, ISP + +_Locales = Optional[Sequence[Text]] + +class Reader: + def __init__(self, filename: Text, locales: _Locales = ..., mode: int = ...) -> None: ... + def __enter__(self) -> Reader: ... + def __exit__(self, exc_type: Optional[Type[BaseException]] = ..., exc_val: Optional[BaseException] = ..., exc_tb: Optional[TracebackType] = ...) -> None: ... + def country(self, ip_address: Text) -> Country: ... + def city(self, ip_address: Text) -> City: ... + def anonymous_ip(self, ip_address: Text) -> AnonymousIP: ... + def asn(self, ip_address: Text) -> ASN: ... + def connection_type(self, ip_address: Text) -> ConnectionType: ... + def domain(self, ip_address: Text) -> Domain: ... + def enterprise(self, ip_address: Text) -> Enterprise: ... + def isp(self, ip_address: Text) -> ISP: ... + def metadata(self) -> Metadata: ... + def close(self) -> None: ... diff --git a/third_party/2and3/geoip2/errors.pyi b/third_party/2and3/geoip2/errors.pyi new file mode 100644 index 000000000..d5b703c30 --- /dev/null +++ b/third_party/2and3/geoip2/errors.pyi @@ -0,0 +1,18 @@ +from typing import Optional, Text + +class GeoIP2Error(RuntimeError): ... + +class AddressNotFoundError(GeoIP2Error): ... + +class AuthenticationError(GeoIP2Error): ... + +class HTTPError(GeoIP2Error): + http_status: Optional[int] + uri: Optional[Text] + def __init__(self, message: Text, http_status: Optional[int] = ..., uri: Optional[Text] = ...) -> None: ... + +class InvalidRequestError(GeoIP2Error): ... + +class OutOfQueriesError(GeoIP2Error): ... + +class PermissionRequiredError(GeoIP2Error): ... diff --git a/third_party/2and3/geoip2/mixins.pyi b/third_party/2and3/geoip2/mixins.pyi new file mode 100644 index 000000000..8c683c26b --- /dev/null +++ b/third_party/2and3/geoip2/mixins.pyi @@ -0,0 +1,3 @@ +class SimpleEquality: + def __eq__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... diff --git a/third_party/2and3/geoip2/models.pyi b/third_party/2and3/geoip2/models.pyi new file mode 100644 index 000000000..d9330ef8f --- /dev/null +++ b/third_party/2and3/geoip2/models.pyi @@ -0,0 +1,65 @@ +from typing import Any, Mapping, Optional, Sequence, Text + +from geoip2 import records + +from geoip2.mixins import SimpleEquality + +_Locales = Optional[Sequence[Text]] +_RawResponse = Mapping[Text, Mapping[Text, Any]] + +class Country(SimpleEquality): + continent: records.Continent + country: records.Country + registered_country: records.Country + represented_country: records.RepresentedCountry + maxmind: records.MaxMind + traits: records.Traits + raw: _RawResponse + def __init__(self, raw_response: _RawResponse, locales: _Locales = ...) -> None: ... + +class City(Country): + city: records.City + location: records.Location + postal: records.Postal + subdivisions: records.Subdivisions + def __init__(self, raw_response: _RawResponse, locales: _Locales = ...) -> None: ... + +class Insights(City): ... + +class Enterprise(City): ... + +class SimpleModel(SimpleEquality): ... + +class AnonymousIP(SimpleModel): + is_anonymous: bool + is_anonymous_vpn: bool + is_hosting_provider: bool + is_public_proxy: bool + is_tor_exit_node: bool + ip_address: Optional[Text] + raw: _RawResponse + def __init__(self, raw: _RawResponse) -> None: ... + +class ASN(SimpleModel): + autonomous_system_number: Optional[int] + autonomous_system_organization: Optional[Text] + ip_address: Optional[Text] + raw: _RawResponse + def __init__(self, raw: _RawResponse) -> None: ... + +class ConnectionType(SimpleModel): + connection_type: Optional[Text] + ip_address: Optional[Text] + raw: _RawResponse + def __init__(self, raw: _RawResponse) -> None: ... + +class Domain(SimpleModel): + domain: Optional[Text] + ip_address: Optional[Text] + raw: Optional[Text] + def __init__(self, raw: _RawResponse) -> None: ... + +class ISP(ASN): + isp: Optional[Text] + organization: Optional[Text] + def __init__(self, raw: _RawResponse) -> None: ... diff --git a/third_party/2and3/geoip2/records.pyi b/third_party/2and3/geoip2/records.pyi new file mode 100644 index 000000000..0d90b18ca --- /dev/null +++ b/third_party/2and3/geoip2/records.pyi @@ -0,0 +1,83 @@ +from typing import Any, Mapping, Optional, Sequence, Text, Tuple + +from geoip2.mixins import SimpleEquality + +_Locales = Optional[Sequence[Text]] +_Names = Mapping[Text, Text] + +class Record(SimpleEquality): + def __init__(self, **kwargs: Any) -> None: ... + def __setattr__(self, name: Text, value: Any) -> None: ... + +class PlaceRecord(Record): + def __init__(self, locales: _Locales = ..., **kwargs: Any) -> None: ... + @property + def name(self) -> Text: ... + +class City(PlaceRecord): + confidence: int + geoname_id: int + names: _Names + +class Continent(PlaceRecord): + code: Text + geoname_id: int + names: _Names + +class Country(PlaceRecord): + confidence: int + geoname_id: int + is_in_european_union: bool + iso_code: Text + names: _Names + def __init__(self, locales: _Locales = ..., **kwargs: Any) -> None: ... + +class RepresentedCountry(Country): + type: Text + +class Location(Record): + average_income: int + accuracy_radius: int + latitude: float + longitude: float + metro_code: int + population_density: int + time_zone: Text + +class MaxMind(Record): + queries_remaining: int + +class Postal(Record): + code: Text + confidence: int + +class Subdivision(PlaceRecord): + confidence: int + geoname_id: int + iso_code: Text + names: _Names + +class Subdivisions(Tuple[Subdivision]): + def __new__(cls, locales: _Locales, *subdivisions: Subdivision) -> Subdivisions: ... + def __init__(self, locales: _Locales, *subdivisions: Subdivision) -> None: ... + @property + def most_specific(self) -> Subdivision: ... + +class Traits(Record): + autonomous_system_number: int + autonomous_system_organization: Text + connection_type: Text + domain: Text + ip_address: Text + is_anonymous: bool + is_anonymous_proxy: bool + is_anonymous_vpn: bool + is_hosting_provider: bool + is_legitimate_proxy: bool + is_public_proxy: bool + is_satellite_provider: bool + is_tor_exit_node: bool + isp: Text + organization: Text + user_type: Text + def __init__(self, **kwargs: Any) -> None: ... diff --git a/third_party/2and3/maxminddb/__init__.pyi b/third_party/2and3/maxminddb/__init__.pyi new file mode 100644 index 000000000..fe20a1f42 --- /dev/null +++ b/third_party/2and3/maxminddb/__init__.pyi @@ -0,0 +1,7 @@ +from typing import Text + +from maxminddb import reader + +def open_database(database: Text, mode: int = ...) -> reader.Reader: ... + +def Reader(database: Text) -> reader.Reader: ... diff --git a/third_party/3/maxminddb/compat.pyi b/third_party/2and3/maxminddb/compat.pyi similarity index 85% rename from third_party/3/maxminddb/compat.pyi rename to third_party/2and3/maxminddb/compat.pyi index 236b0797e..ca8e3ab2c 100644 --- a/third_party/3/maxminddb/compat.pyi +++ b/third_party/2and3/maxminddb/compat.pyi @@ -1,5 +1,3 @@ -# Stubs for maxminddb.compat (Python 3) - from ipaddress import IPv4Address, IPv6Address from typing import Any diff --git a/third_party/3/maxminddb/const.pyi b/third_party/2and3/maxminddb/const.pyi similarity index 76% rename from third_party/3/maxminddb/const.pyi rename to third_party/2and3/maxminddb/const.pyi index 36d11a7fa..e1cff069a 100644 --- a/third_party/3/maxminddb/const.pyi +++ b/third_party/2and3/maxminddb/const.pyi @@ -1,5 +1,3 @@ -# Stubs for maxminddb.const (Python 3) - MODE_AUTO: int = ... MODE_MMAP_EXT: int = ... MODE_MMAP: int = ... diff --git a/third_party/3/maxminddb/decoder.pyi b/third_party/2and3/maxminddb/decoder.pyi similarity index 83% rename from third_party/3/maxminddb/decoder.pyi rename to third_party/2and3/maxminddb/decoder.pyi index 1b7aa6e15..e2bc38adb 100644 --- a/third_party/3/maxminddb/decoder.pyi +++ b/third_party/2and3/maxminddb/decoder.pyi @@ -1,5 +1,3 @@ -# Stubs for maxminddb.decoder (Python 3) - from typing import Any, Tuple class Decoder: diff --git a/third_party/3/maxminddb/errors.pyi b/third_party/2and3/maxminddb/errors.pyi similarity index 52% rename from third_party/3/maxminddb/errors.pyi rename to third_party/2and3/maxminddb/errors.pyi index 46b1f5aee..e98b5560d 100644 --- a/third_party/3/maxminddb/errors.pyi +++ b/third_party/2and3/maxminddb/errors.pyi @@ -1,3 +1 @@ -# Stubs for maxminddb.errors (Python 3) - class InvalidDatabaseError(RuntimeError): ... diff --git a/third_party/3/maxminddb/extension.pyi b/third_party/2and3/maxminddb/extension.pyi similarity index 80% rename from third_party/3/maxminddb/extension.pyi rename to third_party/2and3/maxminddb/extension.pyi index 24fb85180..de4423c34 100644 --- a/third_party/3/maxminddb/extension.pyi +++ b/third_party/2and3/maxminddb/extension.pyi @@ -1,6 +1,4 @@ -# Stubs for maxminddb.extension (Python 3) - -from typing import Any, Mapping, Sequence +from typing import Any, Mapping, Sequence, Text from maxminddb.errors import InvalidDatabaseError as InvalidDatabaseError @@ -21,9 +19,9 @@ class extension: @property def ip_version(self) -> int: ... @property - def database_type(self) -> str: ... + def database_type(self) -> Text: ... @property - def languages(self) -> Sequence[str]: ... + def languages(self) -> Sequence[Text]: ... @property def binary_format_major_version(self) -> int: ... @property @@ -31,5 +29,5 @@ class extension: @property def build_epoch(self) -> int: ... @property - def description(self) -> Mapping[str, str]: ... + def description(self) -> Mapping[Text, Text]: ... def __init__(self, **kwargs: Any) -> None: ... diff --git a/third_party/3/maxminddb/reader.pyi b/third_party/2and3/maxminddb/reader.pyi similarity index 66% rename from third_party/3/maxminddb/reader.pyi rename to third_party/2and3/maxminddb/reader.pyi index 47e7f6493..882a49876 100644 --- a/third_party/3/maxminddb/reader.pyi +++ b/third_party/2and3/maxminddb/reader.pyi @@ -1,16 +1,14 @@ -# Stubs for maxminddb.reader (Python 3) - from ipaddress import IPv4Address, IPv6Address from types import TracebackType -from typing import Any, Mapping, Optional, Sequence, Tuple, Type, Union +from typing import Any, Mapping, Optional, Sequence, Text, Tuple, Type, Union class Reader: closed: bool = ... def __init__(self, database: bytes, mode: int = ...) -> None: ... def metadata(self) -> Metadata: ... - def get(self, ip_address: Union[str, IPv4Address, IPv6Address]) -> Optional[Any]: ... - def get_with_prefix_len(self, ip_address: Union[str, IPv4Address, IPv6Address]) -> Tuple[Optional[Any], int]: ... + def get(self, ip_address: Union[Text, IPv4Address, IPv6Address]) -> Optional[Any]: ... + def get_with_prefix_len(self, ip_address: Union[Text, IPv4Address, IPv6Address]) -> Tuple[Optional[Any], int]: ... def close(self) -> None: ... def __enter__(self) -> Reader: ... def __exit__(self, exc_type: Optional[Type[BaseException]] = ..., exc_val: Optional[BaseException] = ..., exc_tb: Optional[TracebackType] = ...) -> None: ... @@ -19,12 +17,12 @@ class Metadata: node_count: int = ... record_size: int = ... ip_version: int = ... - database_type: str = ... - languages: Sequence[str] = ... + database_type: Text = ... + languages: Sequence[Text] = ... binary_format_major_version: int = ... binary_format_minor_version: int = ... build_epoch: int = ... - description: Mapping[str, str] = ... + description: Mapping[Text, Text] = ... def __init__(self, **kwargs: Any) -> None: ... @property def node_byte_size(self) -> int: ... diff --git a/third_party/3/maxminddb/__init__.pyi b/third_party/3/maxminddb/__init__.pyi deleted file mode 100644 index 040872fed..000000000 --- a/third_party/3/maxminddb/__init__.pyi +++ /dev/null @@ -1,9 +0,0 @@ -# Stubs for maxminddb (Python 3) - -from typing import Any - -from maxminddb import reader - -def open_database(database: str, mode: int = ...) -> reader.Reader: ... - -def Reader(database: str) -> reader.Reader: ...