Skip to content

Commit 79751c5

Browse files
authored
Merge pull request #207 from maxmind/greg/eng-1922
Switch to ruff for formatting and linting
2 parents 09456ae + 18be8eb commit 79751c5

File tree

15 files changed

+436
-504
lines changed

15 files changed

+436
-504
lines changed

.gitignore

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@ geoip2.egg-info/
1313
MANIFEST
1414
.mypy_cache/
1515
*.pyc
16-
pylint.txt
1716
.pyre
1817
.pytype
1918
*.swp
2019
.tox
21-
violations.pyflakes.txt
22-
/venv
20+
/venv

examples/benchmark.py

100644100755
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/python
2-
2+
"""Simple benchmarking script."""
33

44
import argparse
55
import contextlib
@@ -9,6 +9,7 @@
99
import timeit
1010

1111
import geoip2.database
12+
import geoip2.errors
1213

1314
parser = argparse.ArgumentParser(description="Benchmark maxminddb.")
1415
parser.add_argument("--count", default=250000, type=int, help="number of lookups")
@@ -21,6 +22,7 @@
2122

2223

2324
def lookup_ip_address() -> None:
25+
"""Look up IP address."""
2426
ip = socket.inet_ntoa(struct.pack("!L", random.getrandbits(32)))
2527
with contextlib.suppress(geoip2.errors.AddressNotFoundError):
2628
reader.city(str(ip))
@@ -32,4 +34,4 @@ def lookup_ip_address() -> None:
3234
number=args.count,
3335
)
3436

35-
print(args.count / elapsed, "lookups per second")
37+
print(args.count / elapsed, "lookups per second") # noqa: T201

geoip2/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# pylint:disable=C0111
1+
"""geoip2 client library."""
22

33
__title__ = "geoip2"
44
__version__ = "5.1.0"

geoip2/_internal.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
11
"""Internal utilities."""
22

3-
# pylint: disable=too-few-public-methods
43
from abc import ABCMeta
54

65

7-
class Model(metaclass=ABCMeta):
6+
class Model(metaclass=ABCMeta): # noqa: B024
87
"""Shared methods for MaxMind model classes."""
98

109
def __eq__(self, other: object) -> bool:
1110
return isinstance(other, self.__class__) and self.to_dict() == other.to_dict()
1211

13-
def __ne__(self, other) -> bool:
12+
def __ne__(self, other: object) -> bool:
1413
return not self.__eq__(other)
1514

16-
# pylint: disable=too-many-branches
17-
def to_dict(self) -> dict:
15+
def to_dict(self) -> dict: # noqa: C901, PLR0912
1816
"""Return a dict of the object suitable for serialization."""
1917
result = {}
2018
for key, value in self.__dict__.items():
@@ -42,7 +40,6 @@ def to_dict(self) -> dict:
4240
result[key] = value
4341

4442
# network and ip_address are properties for performance reasons
45-
# pylint: disable=no-member
4643
if hasattr(self, "ip_address") and self.ip_address is not None:
4744
result["ip_address"] = str(self.ip_address)
4845
if hasattr(self, "network") and self.network is not None:

geoip2/database.py

Lines changed: 52 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
"""The database reader for MaxMind MMDB files."""
22

3+
from __future__ import annotations
4+
35
import inspect
4-
import os
5-
from collections.abc import Sequence
6-
from typing import IO, Any, AnyStr, Optional, Union, cast
6+
from typing import IO, TYPE_CHECKING, AnyStr, cast
77

88
import maxminddb
99
from maxminddb import (
@@ -13,23 +13,31 @@
1313
MODE_MEMORY,
1414
MODE_MMAP,
1515
MODE_MMAP_EXT,
16+
InvalidDatabaseError,
1617
)
1718

1819
import geoip2
1920
import geoip2.errors
2021
import geoip2.models
21-
from geoip2.models import (
22-
ASN,
23-
ISP,
24-
AnonymousIP,
25-
AnonymousPlus,
26-
City,
27-
ConnectionType,
28-
Country,
29-
Domain,
30-
Enterprise,
31-
)
32-
from geoip2.types import IPAddress
22+
23+
if TYPE_CHECKING:
24+
import os
25+
from collections.abc import Sequence
26+
27+
from typing_extensions import Self
28+
29+
from geoip2.models import (
30+
ASN,
31+
ISP,
32+
AnonymousIP,
33+
AnonymousPlus,
34+
City,
35+
ConnectionType,
36+
Country,
37+
Domain,
38+
Enterprise,
39+
)
40+
from geoip2.types import IPAddress
3341

3442
__all__ = [
3543
"MODE_AUTO",
@@ -67,8 +75,8 @@ class Reader:
6775

6876
def __init__(
6977
self,
70-
fileish: Union[AnyStr, int, os.PathLike, IO],
71-
locales: Optional[Sequence[str]] = None,
78+
fileish: AnyStr | int | os.PathLike | IO,
79+
locales: Sequence[str] | None = None,
7280
mode: int = MODE_AUTO,
7381
) -> None:
7482
"""Create GeoIP2 Reader.
@@ -117,10 +125,10 @@ def __init__(
117125
self._db_type = self._db_reader.metadata().database_type
118126
self._locales = locales
119127

120-
def __enter__(self) -> "Reader":
128+
def __enter__(self) -> Self:
121129
return self
122130

123-
def __exit__(self, exc_type: None, exc_value: None, traceback: None) -> None:
131+
def __exit__(self, exc_type: object, exc_value: object, traceback: object) -> None:
124132
self.close()
125133

126134
def country(self, ip_address: IPAddress) -> Country:
@@ -132,7 +140,7 @@ def country(self, ip_address: IPAddress) -> Country:
132140
133141
"""
134142
return cast(
135-
Country,
143+
"Country",
136144
self._model_for(geoip2.models.Country, "Country", ip_address),
137145
)
138146

@@ -144,7 +152,7 @@ def city(self, ip_address: IPAddress) -> City:
144152
:returns: :py:class:`geoip2.models.City` object
145153
146154
"""
147-
return cast(City, self._model_for(geoip2.models.City, "City", ip_address))
155+
return cast("City", self._model_for(geoip2.models.City, "City", ip_address))
148156

149157
def anonymous_ip(self, ip_address: IPAddress) -> AnonymousIP:
150158
"""Get the AnonymousIP object for the IP address.
@@ -155,7 +163,7 @@ def anonymous_ip(self, ip_address: IPAddress) -> AnonymousIP:
155163
156164
"""
157165
return cast(
158-
AnonymousIP,
166+
"AnonymousIP",
159167
self._flat_model_for(
160168
geoip2.models.AnonymousIP,
161169
"GeoIP2-Anonymous-IP",
@@ -172,7 +180,7 @@ def anonymous_plus(self, ip_address: IPAddress) -> AnonymousPlus:
172180
173181
"""
174182
return cast(
175-
AnonymousPlus,
183+
"AnonymousPlus",
176184
self._flat_model_for(
177185
geoip2.models.AnonymousPlus,
178186
"GeoIP-Anonymous-Plus",
@@ -189,7 +197,7 @@ def asn(self, ip_address: IPAddress) -> ASN:
189197
190198
"""
191199
return cast(
192-
ASN,
200+
"ASN",
193201
self._flat_model_for(geoip2.models.ASN, "GeoLite2-ASN", ip_address),
194202
)
195203

@@ -202,7 +210,7 @@ def connection_type(self, ip_address: IPAddress) -> ConnectionType:
202210
203211
"""
204212
return cast(
205-
ConnectionType,
213+
"ConnectionType",
206214
self._flat_model_for(
207215
geoip2.models.ConnectionType,
208216
"GeoIP2-Connection-Type",
@@ -219,7 +227,7 @@ def domain(self, ip_address: IPAddress) -> Domain:
219227
220228
"""
221229
return cast(
222-
Domain,
230+
"Domain",
223231
self._flat_model_for(geoip2.models.Domain, "GeoIP2-Domain", ip_address),
224232
)
225233

@@ -232,7 +240,7 @@ def enterprise(self, ip_address: IPAddress) -> Enterprise:
232240
233241
"""
234242
return cast(
235-
Enterprise,
243+
"Enterprise",
236244
self._model_for(geoip2.models.Enterprise, "Enterprise", ip_address),
237245
)
238246

@@ -245,31 +253,38 @@ def isp(self, ip_address: IPAddress) -> ISP:
245253
246254
"""
247255
return cast(
248-
ISP,
256+
"ISP",
249257
self._flat_model_for(geoip2.models.ISP, "GeoIP2-ISP", ip_address),
250258
)
251259

252-
def _get(self, database_type: str, ip_address: IPAddress) -> Any:
260+
def _get(self, database_type: str, ip_address: IPAddress) -> tuple[dict, int]:
253261
if database_type not in self._db_type:
254262
caller = inspect.stack()[2][3]
263+
msg = (
264+
f"The {caller} method cannot be used with the {self._db_type} database"
265+
)
255266
raise TypeError(
256-
f"The {caller} method cannot be used with the {self._db_type} database",
267+
msg,
257268
)
258269
(record, prefix_len) = self._db_reader.get_with_prefix_len(ip_address)
259270
if record is None:
271+
msg = f"The address {ip_address} is not in the database."
260272
raise geoip2.errors.AddressNotFoundError(
261-
f"The address {ip_address} is not in the database.",
273+
msg,
262274
str(ip_address),
263275
prefix_len,
264276
)
277+
if not isinstance(record, dict):
278+
msg = f"Expected record to be a dict but was f{type(record)}"
279+
raise InvalidDatabaseError(msg)
265280
return record, prefix_len
266281

267282
def _model_for(
268283
self,
269-
model_class: Union[type[Country], type[Enterprise], type[City]],
284+
model_class: type[City | Country | Enterprise],
270285
types: str,
271286
ip_address: IPAddress,
272-
) -> Union[Country, Enterprise, City]:
287+
) -> City | Country | Enterprise:
273288
(record, prefix_len) = self._get(types, ip_address)
274289
return model_class(
275290
self._locales,
@@ -280,28 +295,22 @@ def _model_for(
280295

281296
def _flat_model_for(
282297
self,
283-
model_class: Union[
284-
type[Domain],
285-
type[ISP],
286-
type[ConnectionType],
287-
type[ASN],
288-
type[AnonymousIP],
289-
],
298+
model_class: type[Domain | ISP | ConnectionType | ASN | AnonymousIP],
290299
types: str,
291300
ip_address: IPAddress,
292-
) -> Union[ConnectionType, ISP, AnonymousIP, Domain, ASN]:
301+
) -> ConnectionType | ISP | AnonymousIP | Domain | ASN:
293302
(record, prefix_len) = self._get(types, ip_address)
294303
return model_class(ip_address, prefix_len=prefix_len, **record)
295304

296305
def metadata(
297306
self,
298307
) -> maxminddb.reader.Metadata:
299-
"""The metadata for the open database.
308+
"""Get the metadata for the open database.
300309
301310
:returns: :py:class:`maxminddb.reader.Metadata` object
302311
"""
303312
return self._db_reader.metadata()
304313

305314
def close(self) -> None:
306-
"""Closes the GeoIP2 database."""
315+
"""Close the GeoIP2 database."""
307316
self._db_reader.close()

0 commit comments

Comments
 (0)