Skip to content

Commit 657aeb8

Browse files
authored
Merge pull request #280 from maxmind/greg/eng-3427
Update Python version and maxminddb
2 parents 8de8724 + 7dab9f5 commit 657aeb8

File tree

10 files changed

+142
-263
lines changed

10 files changed

+142
-263
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
strategy:
1616
fail-fast: false
1717
matrix:
18-
env: [3.9, "3.10", 3.11, 3.12, 3.13]
18+
env: ["3.10", 3.11, 3.12, 3.13, 3.14]
1919
os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest, windows-latest]
2020
steps:
2121
- uses: actions/checkout@v5

HISTORY.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ History
77
5.2.0
88
++++++++++++++++++
99

10+
* IMPORTANT: Python 3.10 or greater is required. If you are using an older
11+
version, please use an earlier release.
12+
* `maxminddb` has been upgraded to 3.0.0. This includes free-threading
13+
support.
1014
* Setuptools has been replaced with the uv build backend for building the
1115
package.
1216

pyproject.toml

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ authors = [
77
]
88
dependencies = [
99
"aiohttp>=3.6.2,<4.0.0",
10-
"maxminddb>=2.7.0,<3.0.0",
10+
"maxminddb>=3.0.0,<4.0.0",
1111
"requests>=2.24.0,<3.0.0",
1212
]
13-
requires-python = ">=3.9"
13+
requires-python = ">=3.10"
1414
readme = "README.rst"
1515
license = "Apache-2.0"
1616
license-files = ["LICENSE"]
@@ -21,11 +21,11 @@ classifiers = [
2121
"Intended Audience :: System Administrators",
2222
"Programming Language :: Python",
2323
"Programming Language :: Python :: 3",
24-
"Programming Language :: Python :: 3.9",
2524
"Programming Language :: Python :: 3.10",
2625
"Programming Language :: Python :: 3.11",
2726
"Programming Language :: Python :: 3.12",
2827
"Programming Language :: Python :: 3.13",
28+
"Programming Language :: Python :: 3.14",
2929
"Topic :: Internet",
3030
"Topic :: Internet :: Proxy Servers",
3131
]
@@ -65,9 +65,6 @@ Documentation = "https://geoip2.readthedocs.org/"
6565
[tool.ruff.lint]
6666
select = ["ALL"]
6767
ignore = [
68-
# Skip type annotation on **_
69-
"ANN003",
70-
7168
# Redundant as the formatter handles missing trailing commas.
7269
"COM812",
7370

@@ -90,16 +87,16 @@ ignore = [
9087

9188
[tool.ruff.lint.per-file-ignores]
9289
"docs/*" = ["ALL"]
93-
"src/geoip2/{models,records}.py" = [ "D107", "PLR0913" ]
90+
"src/geoip2/{models,records}.py" = [ "ANN401", "D107", "PLR0913" ]
9491
"tests/*" = ["ANN201", "D"]
9592

9693
[tool.tox]
9794
env_list = [
98-
"3.9",
9995
"3.10",
10096
"3.11",
10197
"3.12",
10298
"3.13",
99+
"3.14",
103100
"lint",
104101
]
105102
skip_missing_interpreters = false
@@ -114,7 +111,7 @@ commands = [
114111

115112
[tool.tox.env.lint]
116113
description = "Code linting"
117-
python = "3.13"
114+
python = "3.14"
118115
dependency_groups = [
119116
"dev",
120117
"lint",
@@ -126,8 +123,8 @@ commands = [
126123
]
127124

128125
[tool.tox.gh.python]
129-
"3.13" = ["3.13", "lint"]
126+
"3.14" = ["3.14", "lint"]
127+
"3.13" = ["3.13"]
130128
"3.12" = ["3.12"]
131129
"3.11" = ["3.11"]
132130
"3.10" = ["3.10"]
133-
"3.9" = ["3.9"]

src/geoip2/_internal.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import json
44
from abc import ABCMeta
5+
from typing import Any
56

67

78
class Model(metaclass=ABCMeta): # noqa: B024
@@ -17,7 +18,7 @@ def __hash__(self) -> int:
1718
# This is not particularly efficient, but I don't expect it to be used much.
1819
return hash(json.dumps(self.to_dict(), sort_keys=True))
1920

20-
def to_dict(self) -> dict: # noqa: C901, PLR0912
21+
def to_dict(self) -> dict[str, Any]: # noqa: C901, PLR0912
2122
"""Return a dict of the object suitable for serialization."""
2223
result = {}
2324
for key, value in self.__dict__.items():

src/geoip2/database.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ class Reader:
7575

7676
def __init__(
7777
self,
78-
fileish: AnyStr | int | os.PathLike | IO,
78+
fileish: (
79+
AnyStr | int | os.PathLike[str] | os.PathLike[bytes] | IO[str] | IO[bytes]
80+
),
7981
locales: Sequence[str] | None = None,
8082
mode: int = MODE_AUTO,
8183
) -> None:

src/geoip2/models.py

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import ipaddress
1212
from abc import ABCMeta
1313
from ipaddress import IPv4Address, IPv6Address
14-
from typing import TYPE_CHECKING
14+
from typing import TYPE_CHECKING, Any
1515

1616
import geoip2.records
1717
from geoip2._internal import Model
@@ -55,15 +55,15 @@ def __init__(
5555
self,
5656
locales: Sequence[str] | None,
5757
*,
58-
continent: dict | None = None,
59-
country: dict | None = None,
58+
continent: dict[str, Any] | None = None,
59+
country: dict[str, Any] | None = None,
6060
ip_address: IPAddress | None = None,
61-
maxmind: dict | None = None,
61+
maxmind: dict[str, Any] | None = None,
6262
prefix_len: int | None = None,
63-
registered_country: dict | None = None,
64-
represented_country: dict | None = None,
65-
traits: dict | None = None,
66-
**_,
63+
registered_country: dict[str, Any] | None = None,
64+
represented_country: dict[str, Any] | None = None,
65+
traits: dict[str, Any] | None = None,
66+
**_: Any,
6767
) -> None:
6868
self._locales = locales
6969
self.continent = geoip2.records.Continent(locales, **(continent or {}))
@@ -115,19 +115,19 @@ def __init__(
115115
self,
116116
locales: Sequence[str] | None,
117117
*,
118-
city: dict | None = None,
119-
continent: dict | None = None,
120-
country: dict | None = None,
121-
location: dict | None = None,
118+
city: dict[str, Any] | None = None,
119+
continent: dict[str, Any] | None = None,
120+
country: dict[str, Any] | None = None,
121+
location: dict[str, Any] | None = None,
122122
ip_address: IPAddress | None = None,
123-
maxmind: dict | None = None,
124-
postal: dict | None = None,
123+
maxmind: dict[str, Any] | None = None,
124+
postal: dict[str, Any] | None = None,
125125
prefix_len: int | None = None,
126-
registered_country: dict | None = None,
127-
represented_country: dict | None = None,
128-
subdivisions: list[dict] | None = None,
129-
traits: dict | None = None,
130-
**_,
126+
registered_country: dict[str, Any] | None = None,
127+
represented_country: dict[str, Any] | None = None,
128+
subdivisions: list[dict[str, Any]] | None = None,
129+
traits: dict[str, Any] | None = None,
130+
**_: Any,
131131
) -> None:
132132
super().__init__(
133133
locales,
@@ -260,7 +260,7 @@ def __init__(
260260
is_tor_exit_node: bool = False,
261261
network: str | None = None,
262262
prefix_len: int | None = None,
263-
**_,
263+
**_: Any,
264264
) -> None:
265265
super().__init__(ip_address, network, prefix_len)
266266
self.is_anonymous = is_anonymous
@@ -304,7 +304,7 @@ def __init__(
304304
network_last_seen: str | None = None,
305305
prefix_len: int | None = None,
306306
provider_name: str | None = None,
307-
**_,
307+
**_: Any,
308308
) -> None:
309309
super().__init__(
310310
is_anonymous=is_anonymous,
@@ -342,7 +342,7 @@ def __init__(
342342
autonomous_system_organization: str | None = None,
343343
network: str | None = None,
344344
prefix_len: int | None = None,
345-
**_,
345+
**_: Any,
346346
) -> None:
347347
super().__init__(ip_address, network, prefix_len)
348348
self.autonomous_system_number = autonomous_system_number
@@ -371,7 +371,7 @@ def __init__(
371371
connection_type: str | None = None,
372372
network: str | None = None,
373373
prefix_len: int | None = None,
374-
**_,
374+
**_: Any,
375375
) -> None:
376376
super().__init__(ip_address, network, prefix_len)
377377
self.connection_type = connection_type
@@ -390,7 +390,7 @@ def __init__(
390390
domain: str | None = None,
391391
network: str | None = None,
392392
prefix_len: int | None = None,
393-
**_,
393+
**_: Any,
394394
) -> None:
395395
super().__init__(ip_address, network, prefix_len)
396396
self.domain = domain
@@ -429,7 +429,7 @@ def __init__(
429429
organization: str | None = None,
430430
network: str | None = None,
431431
prefix_len: int | None = None,
432-
**_,
432+
**_: Any,
433433
) -> None:
434434
super().__init__(
435435
autonomous_system_number=autonomous_system_number,

src/geoip2/records.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import ipaddress
66
from abc import ABCMeta
77
from ipaddress import IPv4Address, IPv6Address
8-
from typing import TYPE_CHECKING
8+
from typing import TYPE_CHECKING, Any
99

1010
from geoip2._internal import Model
1111

@@ -73,7 +73,7 @@ def __init__(
7373
confidence: int | None = None,
7474
geoname_id: int | None = None,
7575
names: dict[str, str] | None = None,
76-
**_,
76+
**_: Any,
7777
) -> None:
7878
self.confidence = confidence
7979
self.geoname_id = geoname_id
@@ -101,7 +101,7 @@ def __init__(
101101
code: str | None = None,
102102
geoname_id: int | None = None,
103103
names: dict[str, str] | None = None,
104-
**_,
104+
**_: Any,
105105
) -> None:
106106
self.code = code
107107
self.geoname_id = geoname_id
@@ -138,7 +138,7 @@ def __init__(
138138
is_in_european_union: bool = False,
139139
iso_code: str | None = None,
140140
names: dict[str, str] | None = None,
141-
**_,
141+
**_: Any,
142142
) -> None:
143143
self.confidence = confidence
144144
self.geoname_id = geoname_id
@@ -171,7 +171,7 @@ def __init__(
171171
iso_code: str | None = None,
172172
names: dict[str, str] | None = None,
173173
type: str | None = None, # noqa: A002
174-
**_,
174+
**_: Any,
175175
) -> None:
176176
self.type = type
177177
super().__init__(
@@ -238,7 +238,7 @@ def __init__(
238238
metro_code: int | None = None,
239239
population_density: int | None = None,
240240
time_zone: str | None = None,
241-
**_,
241+
**_: Any,
242242
) -> None:
243243
self.average_income = average_income
244244
self.accuracy_radius = accuracy_radius
@@ -257,7 +257,7 @@ class MaxMind(Record):
257257
calling.
258258
"""
259259

260-
def __init__(self, *, queries_remaining: int | None = None, **_) -> None:
260+
def __init__(self, *, queries_remaining: int | None = None, **_: Any) -> None:
261261
self.queries_remaining = queries_remaining
262262

263263

@@ -285,7 +285,7 @@ def __init__(
285285
*,
286286
code: str | None = None,
287287
confidence: int | None = None,
288-
**_,
288+
**_: Any,
289289
) -> None:
290290
self.code = code
291291
self.confidence = confidence
@@ -319,7 +319,7 @@ def __init__(
319319
geoname_id: int | None = None,
320320
iso_code: str | None = None,
321321
names: dict[str, str] | None = None,
322-
**_,
322+
**_: Any,
323323
) -> None:
324324
self.confidence = confidence
325325
self.geoname_id = geoname_id
@@ -342,7 +342,7 @@ class Subdivisions(tuple): # noqa: SLOT001
342342
def __new__(
343343
cls: type[Self],
344344
locales: Sequence[str] | None,
345-
*subdivisions: dict,
345+
*subdivisions: dict[str, Any],
346346
) -> Self:
347347
"""Create a new Subdivisions instance.
348348
@@ -367,7 +367,7 @@ def __new__(
367367
def __init__(
368368
self,
369369
locales: Sequence[str] | None,
370-
*_: dict,
370+
*_: dict[str, Any],
371371
) -> None:
372372
"""Initialize the Subdivisions instance."""
373373
self._locales = locales
@@ -580,7 +580,7 @@ def __init__(
580580
mobile_country_code: str | None = None,
581581
mobile_network_code: str | None = None,
582582
is_anycast: bool = False,
583-
**_,
583+
**_: Any,
584584
) -> None:
585585
self.autonomous_system_number = autonomous_system_number
586586
self.autonomous_system_organization = autonomous_system_organization

src/geoip2/types.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""Provides types used internally."""
22

33
from ipaddress import IPv4Address, IPv6Address
4-
from typing import Union
54

6-
IPAddress = Union[str, IPv6Address, IPv4Address]
5+
IPAddress = str | IPv6Address | IPv4Address

tests/webservice_test.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import unittest
88
from abc import ABC, abstractmethod
99
from collections import defaultdict
10-
from typing import Callable, ClassVar, cast
10+
from typing import TYPE_CHECKING, ClassVar, cast
1111

1212
import pytest
1313
import pytest_httpserver
@@ -26,6 +26,9 @@
2626
)
2727
from geoip2.webservice import AsyncClient, Client
2828

29+
if TYPE_CHECKING:
30+
from collections.abc import Callable
31+
2932

3033
class TestBaseClient(unittest.TestCase, ABC):
3134
client: AsyncClient | Client

0 commit comments

Comments
 (0)