Skip to content

Commit 0c55ecb

Browse files
committed
Add type annotations throughout code
1 parent 8dc844c commit 0c55ecb

File tree

10 files changed

+283
-163
lines changed

10 files changed

+283
-163
lines changed

geoip2/database.py

Lines changed: 71 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
66
"""
77
import inspect
8+
from typing import Any, cast, List, Optional, Type, Union
89

910
import maxminddb
1011

1112
# pylint: disable=unused-import
12-
from maxminddb import (
13+
from maxminddb import ( # type: ignore
1314
MODE_AUTO,
1415
MODE_MMAP,
1516
MODE_MMAP_EXT,
@@ -21,6 +22,17 @@
2122
import geoip2
2223
import geoip2.models
2324
import geoip2.errors
25+
from geoip2.types import IPAddress
26+
from geoip2.models import (
27+
ASN,
28+
AnonymousIP,
29+
City,
30+
ConnectionType,
31+
Country,
32+
Domain,
33+
Enterprise,
34+
ISP,
35+
)
2436

2537

2638
class Reader(object):
@@ -47,7 +59,9 @@ class Reader(object):
4759
4860
"""
4961

50-
def __init__(self, fileish, locales=None, mode=MODE_AUTO):
62+
def __init__(
63+
self, fileish: str, locales: Optional[List[str]] = None, mode: int = MODE_AUTO
64+
) -> None:
5165
"""Create GeoIP2 Reader.
5266
5367
:param fileish: The string path to the GeoIP2 database, or an existing
@@ -94,13 +108,13 @@ def __init__(self, fileish, locales=None, mode=MODE_AUTO):
94108
self._db_type = self._db_reader.metadata().database_type
95109
self._locales = locales
96110

97-
def __enter__(self):
111+
def __enter__(self) -> "Reader":
98112
return self
99113

100-
def __exit__(self, exc_type, exc_value, traceback):
114+
def __exit__(self, exc_type: None, exc_value: None, traceback: None) -> None:
101115
self.close()
102116

103-
def country(self, ip_address):
117+
def country(self, ip_address: IPAddress) -> Country:
104118
"""Get the Country object for the IP address.
105119
106120
:param ip_address: IPv4 or IPv6 address as a string.
@@ -109,83 +123,101 @@ def country(self, ip_address):
109123
110124
"""
111125

112-
return self._model_for(geoip2.models.Country, "Country", ip_address)
126+
return cast(
127+
Country, self._model_for(geoip2.models.Country, "Country", ip_address)
128+
)
113129

114-
def city(self, ip_address):
130+
def city(self, ip_address: IPAddress) -> City:
115131
"""Get the City object for the IP address.
116132
117133
:param ip_address: IPv4 or IPv6 address as a string.
118134
119135
:returns: :py:class:`geoip2.models.City` object
120136
121137
"""
122-
return self._model_for(geoip2.models.City, "City", ip_address)
138+
return cast(City, self._model_for(geoip2.models.City, "City", ip_address))
123139

124-
def anonymous_ip(self, ip_address):
140+
def anonymous_ip(self, ip_address: IPAddress) -> AnonymousIP:
125141
"""Get the AnonymousIP object for the IP address.
126142
127143
:param ip_address: IPv4 or IPv6 address as a string.
128144
129145
:returns: :py:class:`geoip2.models.AnonymousIP` object
130146
131147
"""
132-
return self._flat_model_for(
133-
geoip2.models.AnonymousIP, "GeoIP2-Anonymous-IP", ip_address
148+
return cast(
149+
AnonymousIP,
150+
self._flat_model_for(
151+
geoip2.models.AnonymousIP, "GeoIP2-Anonymous-IP", ip_address
152+
),
134153
)
135154

136-
def asn(self, ip_address):
155+
def asn(self, ip_address: IPAddress) -> ASN:
137156
"""Get the ASN object for the IP address.
138157
139158
:param ip_address: IPv4 or IPv6 address as a string.
140159
141160
:returns: :py:class:`geoip2.models.ASN` object
142161
143162
"""
144-
return self._flat_model_for(geoip2.models.ASN, "GeoLite2-ASN", ip_address)
163+
return cast(
164+
ASN, self._flat_model_for(geoip2.models.ASN, "GeoLite2-ASN", ip_address)
165+
)
145166

146-
def connection_type(self, ip_address):
167+
def connection_type(self, ip_address: IPAddress) -> ConnectionType:
147168
"""Get the ConnectionType object for the IP address.
148169
149170
:param ip_address: IPv4 or IPv6 address as a string.
150171
151172
:returns: :py:class:`geoip2.models.ConnectionType` object
152173
153174
"""
154-
return self._flat_model_for(
155-
geoip2.models.ConnectionType, "GeoIP2-Connection-Type", ip_address
175+
return cast(
176+
ConnectionType,
177+
self._flat_model_for(
178+
geoip2.models.ConnectionType, "GeoIP2-Connection-Type", ip_address
179+
),
156180
)
157181

158-
def domain(self, ip_address):
182+
def domain(self, ip_address: IPAddress) -> Domain:
159183
"""Get the Domain object for the IP address.
160184
161185
:param ip_address: IPv4 or IPv6 address as a string.
162186
163187
:returns: :py:class:`geoip2.models.Domain` object
164188
165189
"""
166-
return self._flat_model_for(geoip2.models.Domain, "GeoIP2-Domain", ip_address)
190+
return cast(
191+
Domain,
192+
self._flat_model_for(geoip2.models.Domain, "GeoIP2-Domain", ip_address),
193+
)
167194

168-
def enterprise(self, ip_address):
195+
def enterprise(self, ip_address: IPAddress) -> Enterprise:
169196
"""Get the Enterprise object for the IP address.
170197
171198
:param ip_address: IPv4 or IPv6 address as a string.
172199
173200
:returns: :py:class:`geoip2.models.Enterprise` object
174201
175202
"""
176-
return self._model_for(geoip2.models.Enterprise, "Enterprise", ip_address)
203+
return cast(
204+
Enterprise,
205+
self._model_for(geoip2.models.Enterprise, "Enterprise", ip_address),
206+
)
177207

178-
def isp(self, ip_address):
208+
def isp(self, ip_address: IPAddress) -> ISP:
179209
"""Get the ISP object for the IP address.
180210
181211
:param ip_address: IPv4 or IPv6 address as a string.
182212
183213
:returns: :py:class:`geoip2.models.ISP` object
184214
185215
"""
186-
return self._flat_model_for(geoip2.models.ISP, "GeoIP2-ISP", ip_address)
216+
return cast(
217+
ISP, self._flat_model_for(geoip2.models.ISP, "GeoIP2-ISP", ip_address)
218+
)
187219

188-
def _get(self, database_type, ip_address):
220+
def _get(self, database_type: str, ip_address: IPAddress) -> Any:
189221
if database_type not in self._db_type:
190222
caller = inspect.stack()[2][3]
191223
raise TypeError(
@@ -199,27 +231,39 @@ def _get(self, database_type, ip_address):
199231
)
200232
return record, prefix_len
201233

202-
def _model_for(self, model_class, types, ip_address):
234+
def _model_for(
235+
self,
236+
model_class: Union[Type[Country], Type[Enterprise], Type[City]],
237+
types: str,
238+
ip_address: IPAddress,
239+
) -> Union[Country, Enterprise, City]:
203240
(record, prefix_len) = self._get(types, ip_address)
204241
traits = record.setdefault("traits", {})
205242
traits["ip_address"] = ip_address
206243
traits["prefix_len"] = prefix_len
207244
return model_class(record, locales=self._locales)
208245

209-
def _flat_model_for(self, model_class, types, ip_address):
246+
def _flat_model_for(
247+
self,
248+
model_class: Union[
249+
Type[Domain], Type[ISP], Type[ConnectionType], Type[ASN], Type[AnonymousIP]
250+
],
251+
types: str,
252+
ip_address: IPAddress,
253+
) -> Union[ConnectionType, ISP, AnonymousIP, Domain, ASN]:
210254
(record, prefix_len) = self._get(types, ip_address)
211255
record["ip_address"] = ip_address
212256
record["prefix_len"] = prefix_len
213257
return model_class(record)
214258

215-
def metadata(self):
259+
def metadata(self) -> maxminddb.reader.Metadata:
216260
"""The metadata for the open database.
217261
218262
:returns: :py:class:`maxminddb.reader.Metadata` object
219263
"""
220264
return self._db_reader.metadata()
221265

222-
def close(self):
266+
def close(self) -> None:
223267
"""Closes the GeoIP2 database."""
224268

225269
self._db_reader.close()

geoip2/errors.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
55
"""
66

7+
from typing import Optional
8+
79

810
class GeoIP2Error(RuntimeError):
911
"""There was a generic error in GeoIP2.
@@ -33,7 +35,9 @@ class HTTPError(GeoIP2Error):
3335
3436
"""
3537

36-
def __init__(self, message, http_status=None, uri=None):
38+
def __init__(
39+
self, message: str, http_status: Optional[int] = None, uri: Optional[str] = None
40+
) -> None:
3741
super(HTTPError, self).__init__(message)
3842
self.http_status = http_status
3943
self.uri = uri

geoip2/mixins.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
"""This package contains utility mixins"""
22
# pylint: disable=too-few-public-methods
33
from abc import ABCMeta
4+
from typing import Any
45

56

67
class SimpleEquality(object):
78
"""Naive __dict__ equality mixin"""
89

910
__metaclass__ = ABCMeta
1011

11-
def __eq__(self, other):
12+
def __eq__(self, other: Any) -> bool:
1213
return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
1314

1415
def __ne__(self, other):

geoip2/models.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# pylint: disable=too-many-instance-attributes,too-few-public-methods
1414
import ipaddress
1515
from abc import ABCMeta
16+
from typing import Any, Dict, List, Optional, Union
1617

1718
import geoip2.records
1819
from geoip2.mixins import SimpleEquality
@@ -66,7 +67,9 @@ class Country(SimpleEquality):
6667
6768
"""
6869

69-
def __init__(self, raw_response, locales=None):
70+
def __init__(
71+
self, raw_response: Dict[str, Any], locales: Optional[List[str]] = None
72+
) -> None:
7073
if locales is None:
7174
locales = ["en"]
7275
self._locales = locales
@@ -88,7 +91,7 @@ def __init__(self, raw_response, locales=None):
8891
self.traits = geoip2.records.Traits(**raw_response.get("traits", {}))
8992
self.raw = raw_response
9093

91-
def __repr__(self):
94+
def __repr__(self) -> str:
9295
return "{module}.{class_name}({data}, {locales})".format(
9396
module=self.__module__,
9497
class_name=self.__class__.__name__,
@@ -160,7 +163,9 @@ class City(Country):
160163
161164
"""
162165

163-
def __init__(self, raw_response, locales=None):
166+
def __init__(
167+
self, raw_response: Dict[str, Any], locales: Optional[List[str]] = None
168+
) -> None:
164169
super(City, self).__init__(raw_response, locales)
165170
self.city = geoip2.records.City(locales, **raw_response.get("city", {}))
166171
self.location = geoip2.records.Location(**raw_response.get("location", {}))
@@ -303,13 +308,13 @@ class SimpleModel(SimpleEquality):
303308

304309
__metaclass__ = ABCMeta
305310

306-
def __init__(self, raw):
311+
def __init__(self, raw: Dict[str, Union[bool, str, int]]) -> None:
307312
self.raw = raw
308313
self._network = None
309314
self._prefix_len = raw.get("prefix_len")
310315
self.ip_address = raw.get("ip_address")
311316

312-
def __repr__(self):
317+
def __repr__(self) -> str:
313318
# pylint: disable=no-member
314319
return "{module}.{class_name}({data})".format(
315320
module=self.__module__,
@@ -318,7 +323,7 @@ def __repr__(self):
318323
)
319324

320325
@property
321-
def network(self):
326+
def network(self) -> Optional[Union[ipaddress.IPv4Network, ipaddress.IPv6Network]]:
322327
"""The network for the record"""
323328
# This code is duplicated for performance reasons
324329
# pylint: disable=duplicate-code
@@ -391,7 +396,7 @@ class AnonymousIP(SimpleModel):
391396
:type: ipaddress.IPv4Network or ipaddress.IPv6Network
392397
"""
393398

394-
def __init__(self, raw):
399+
def __init__(self, raw: Dict[str, Union[bool, str, int]]) -> None:
395400
super(AnonymousIP, self).__init__(raw)
396401
self.is_anonymous = raw.get("is_anonymous", False)
397402
self.is_anonymous_vpn = raw.get("is_anonymous_vpn", False)
@@ -434,7 +439,7 @@ class ASN(SimpleModel):
434439
"""
435440

436441
# pylint:disable=too-many-arguments
437-
def __init__(self, raw):
442+
def __init__(self, raw: Dict[str, Union[str, int]]) -> None:
438443
super(ASN, self).__init__(raw)
439444
self.autonomous_system_number = raw.get("autonomous_system_number")
440445
self.autonomous_system_organization = raw.get("autonomous_system_organization")
@@ -473,7 +478,7 @@ class ConnectionType(SimpleModel):
473478
:type: ipaddress.IPv4Network or ipaddress.IPv6Network
474479
"""
475480

476-
def __init__(self, raw):
481+
def __init__(self, raw: Dict[str, Union[str, int]]) -> None:
477482
super(ConnectionType, self).__init__(raw)
478483
self.connection_type = raw.get("connection_type")
479484

@@ -505,7 +510,7 @@ class Domain(SimpleModel):
505510
506511
"""
507512

508-
def __init__(self, raw):
513+
def __init__(self, raw: Dict[str, Union[str, int]]) -> None:
509514
super(Domain, self).__init__(raw)
510515
self.domain = raw.get("domain")
511516

@@ -556,7 +561,7 @@ class ISP(ASN):
556561
"""
557562

558563
# pylint:disable=too-many-arguments
559-
def __init__(self, raw):
564+
def __init__(self, raw: Dict[str, Union[str, int]]) -> None:
560565
super(ISP, self).__init__(raw)
561566
self.isp = raw.get("isp")
562567
self.organization = raw.get("organization")

0 commit comments

Comments
 (0)