diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d34a80c..1a21574 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: platform: [ubuntu-latest, macos-latest, windows-latest] - python-version: [3.8, 3.9, "3.10", 3.11, 3.12, 3.13] + python-version: [3.9, "3.10", 3.11, 3.12, 3.13] name: Python ${{ matrix.python-version }} on ${{ matrix.platform }} runs-on: ${{ matrix.platform }} diff --git a/HISTORY.rst b/HISTORY.rst index 67a755a..2ff32b2 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -7,8 +7,12 @@ History 4.9.0 ++++++++++++++++++ +* IMPORTANT: Python 3.9 or greater is required. If you are using an older + version, please use an earlier release. * ``metro_code`` on ``geoip2.record.Location`` has been deprecated. The code values are no longer being maintained. +* The type hinting for the optional ``locales`` keyword argument now allows + any sequence of strings rather than only list of strings. 4.8.1 (2024-11-18) ++++++++++++++++++ diff --git a/README.rst b/README.rst index e1e8913..11d1f14 100644 --- a/README.rst +++ b/README.rst @@ -495,7 +495,7 @@ correction, please `contact MaxMind support Requirements ------------ -Python 3.8 or greater is required. Older versions are not supported. +Python 3.9 or greater is required. Older versions are not supported. The Requests HTTP library is also required. See for details. diff --git a/docs/conf.py b/docs/conf.py index 3989a98..e8526e9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -49,7 +49,7 @@ # General information about the project. project = "geoip2" -copyright = "2013-2024, MaxMind, Inc." +copyright = "2013-2025, MaxMind, Inc." # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/docs/index.rst b/docs/index.rst index 1233f20..a6b91ba 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -38,6 +38,6 @@ Indices and tables * :ref:`modindex` * :ref:`search` -:copyright: (c) 2013-2024 by MaxMind, Inc. +:copyright: (c) 2013-2025 by MaxMind, Inc. :license: Apache License, Version 2.0 diff --git a/geoip2/__init__.py b/geoip2/__init__.py index 7d1a8ad..43c322a 100644 --- a/geoip2/__init__.py +++ b/geoip2/__init__.py @@ -4,4 +4,4 @@ __version__ = "4.8.1" __author__ = "Gregory Oschwald" __license__ = "Apache License, Version 2.0" -__copyright__ = "Copyright (c) 2013-2024 MaxMind, Inc." +__copyright__ = "Copyright (c) 2013-2025 MaxMind, Inc." diff --git a/geoip2/database.py b/geoip2/database.py index d86b6ec..ab98507 100644 --- a/geoip2/database.py +++ b/geoip2/database.py @@ -7,7 +7,7 @@ import inspect import os -from typing import Any, AnyStr, cast, IO, List, Optional, Type, Union +from typing import Any, AnyStr, cast, IO, Optional, Sequence, Type, Union import maxminddb @@ -72,7 +72,7 @@ class Reader: def __init__( self, fileish: Union[AnyStr, int, os.PathLike, IO], - locales: Optional[List[str]] = None, + locales: Optional[Sequence[str]] = None, mode: int = MODE_AUTO, ) -> None: """Create GeoIP2 Reader. diff --git a/geoip2/models.py b/geoip2/models.py index 66c1871..693a305 100644 --- a/geoip2/models.py +++ b/geoip2/models.py @@ -14,7 +14,7 @@ # pylint: disable=too-many-instance-attributes,too-few-public-methods import ipaddress from abc import ABCMeta -from typing import Any, cast, Dict, List, Optional, Union +from typing import Any, cast, Dict, Optional, Sequence, Union import geoip2.records from geoip2.mixins import SimpleEquality @@ -76,7 +76,7 @@ class Country(SimpleEquality): traits: geoip2.records.Traits def __init__( - self, raw_response: Dict[str, Any], locales: Optional[List[str]] = None + self, raw_response: Dict[str, Any], locales: Optional[Sequence[str]] = None ) -> None: if locales is None: locales = ["en"] @@ -182,7 +182,7 @@ class City(Country): subdivisions: geoip2.records.Subdivisions def __init__( - self, raw_response: Dict[str, Any], locales: Optional[List[str]] = None + self, raw_response: Dict[str, Any], locales: Optional[Sequence[str]] = None ) -> None: super().__init__(raw_response, locales) self.city = geoip2.records.City(locales, **raw_response.get("city", {})) diff --git a/geoip2/records.py b/geoip2/records.py index d6bb61e..4481a70 100644 --- a/geoip2/records.py +++ b/geoip2/records.py @@ -11,7 +11,7 @@ # pylint:disable=R0903 from abc import ABCMeta -from typing import Dict, List, Optional, Type, Union +from typing import Dict, Optional, Type, Sequence, Union from geoip2.mixins import SimpleEquality @@ -28,11 +28,11 @@ class PlaceRecord(Record, metaclass=ABCMeta): """All records with :py:attr:`names` subclass :py:class:`PlaceRecord`.""" names: Dict[str, str] - _locales: List[str] + _locales: Sequence[str] def __init__( self, - locales: Optional[List[str]] = None, + locales: Optional[Sequence[str]] = None, names: Optional[Dict[str, str]] = None, ) -> None: if locales is None: @@ -93,7 +93,7 @@ class City(PlaceRecord): def __init__( self, - locales: Optional[List[str]] = None, + locales: Optional[Sequence[str]] = None, confidence: Optional[int] = None, geoname_id: Optional[int] = None, names: Optional[Dict[str, str]] = None, @@ -147,7 +147,7 @@ class Continent(PlaceRecord): def __init__( self, - locales: Optional[List[str]] = None, + locales: Optional[Sequence[str]] = None, code: Optional[str] = None, geoname_id: Optional[int] = None, names: Optional[Dict[str, str]] = None, @@ -217,7 +217,7 @@ class Country(PlaceRecord): def __init__( self, - locales: Optional[List[str]] = None, + locales: Optional[Sequence[str]] = None, confidence: Optional[int] = None, geoname_id: Optional[int] = None, is_in_european_union: bool = False, @@ -298,7 +298,7 @@ class RepresentedCountry(Country): def __init__( self, - locales: Optional[List[str]] = None, + locales: Optional[Sequence[str]] = None, confidence: Optional[int] = None, geoname_id: Optional[int] = None, is_in_european_union: bool = False, @@ -519,7 +519,7 @@ class Subdivision(PlaceRecord): def __init__( self, - locales: Optional[List[str]] = None, + locales: Optional[Sequence[str]] = None, confidence: Optional[int] = None, geoname_id: Optional[int] = None, iso_code: Optional[str] = None, @@ -545,14 +545,14 @@ class Subdivisions(tuple): """ def __new__( - cls: Type["Subdivisions"], locales: Optional[List[str]], *subdivisions + cls: Type["Subdivisions"], locales: Optional[Sequence[str]], *subdivisions ) -> "Subdivisions": subobjs = tuple(Subdivision(locales, **x) for x in subdivisions) obj = super().__new__(cls, subobjs) # type: ignore return obj def __init__( - self, locales: Optional[List[str]], *subdivisions # pylint:disable=W0613 + self, locales: Optional[Sequence[str]], *subdivisions # pylint:disable=W0613 ) -> None: self._locales = locales super().__init__() diff --git a/geoip2/webservice.py b/geoip2/webservice.py index 5ff3098..b390e94 100644 --- a/geoip2/webservice.py +++ b/geoip2/webservice.py @@ -27,7 +27,7 @@ import ipaddress import json -from typing import Any, Dict, cast, List, Optional, Type, Union +from typing import Any, Dict, cast, Optional, Sequence, Type, Union import aiohttp import aiohttp.http @@ -61,7 +61,7 @@ class BaseClient: # pylint: disable=missing-class-docstring, too-few-public-met _account_id: str _host: str _license_key: str - _locales: List[str] + _locales: Sequence[str] _timeout: float def __init__( @@ -69,7 +69,7 @@ def __init__( account_id: int, license_key: str, host: str, - locales: Optional[List[str]], + locales: Optional[Sequence[str]], timeout: float, ) -> None: """Construct a Client.""" @@ -265,7 +265,7 @@ def __init__( # pylint: disable=too-many-arguments,too-many-positional-argument account_id: int, license_key: str, host: str = "geoip.maxmind.com", - locales: Optional[List[str]] = None, + locales: Optional[Sequence[str]] = None, timeout: float = 60, proxy: Optional[str] = None, ) -> None: @@ -428,7 +428,7 @@ def __init__( # pylint: disable=too-many-arguments,too-many-positional-argument account_id: int, license_key: str, host: str = "geoip.maxmind.com", - locales: Optional[List[str]] = None, + locales: Optional[Sequence[str]] = None, timeout: float = 60, proxy: Optional[str] = None, ) -> None: diff --git a/pyproject.toml b/pyproject.toml index 04a27d0..d55b892 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ dependencies = [ "maxminddb>=2.5.1,<3.0.0", "requests>=2.24.0,<3.0.0", ] -requires-python = ">=3.8" +requires-python = ">=3.9" readme = "README.rst" license = {text = "Apache License, Version 2.0"} classifiers = [ @@ -25,7 +25,6 @@ classifiers = [ "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", diff --git a/setup.cfg b/setup.cfg index fe10141..6f275ef 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,11 +9,10 @@ geoip2 = py.typed disable = duplicate-code [tox:tox] -envlist = {py38,py39,py310,py311,py312,py313}-test,py313-{black,lint,flake8,mypy} +envlist = {py39,py310,py311,py312,py313}-test,py313-{black,lint,flake8,mypy} [gh-actions] python = - 3.8: py38 3.9: py39 3.10: py310 3.11: py311 diff --git a/tests/webservice_test.py b/tests/webservice_test.py index 813738f..c50e5fc 100644 --- a/tests/webservice_test.py +++ b/tests/webservice_test.py @@ -4,7 +4,6 @@ import asyncio import copy import ipaddress -import json import sys from typing import cast, Dict import unittest