Skip to content

Commit

Permalink
♻️ Drop python 3.7 & support 3.12 (#122)
Browse files Browse the repository at this point in the history
* ✅ Drop python 3.7

* ➕ Add support for Python 3.12

* ♻️ Update dependencies in requirements files

* Update `pycountry` version to 23.12.11

* ♻️ Refactor imports and caching in color.py and country.py

* 🐛 Update dependencies and remove unused code
  • Loading branch information
yezz123 authored Jan 9, 2024
1 parent 0705e6d commit 5216db3
Show file tree
Hide file tree
Showing 9 changed files with 55 additions and 204 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu, macos, windows]
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']

runs-on: ${{ matrix.os }}-latest
steps:
Expand Down
8 changes: 1 addition & 7 deletions pydantic_extra_types/color.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,8 @@

import math
import re
import sys
from colorsys import hls_to_rgb, rgb_to_hls
from typing import Any, Callable, Tuple, Union, cast

if sys.version_info >= (3, 8): # pragma: no cover
from typing import Literal
else: # pragma: no cover
from typing_extensions import Literal
from typing import Any, Callable, Literal, Tuple, Union, cast

from pydantic import GetJsonSchemaHandler
from pydantic._internal import _repr
Expand Down
98 changes: 6 additions & 92 deletions pydantic_extra_types/country.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from pydantic_core import PydanticCustomError, core_schema

try:
import pycountry # type: ignore[import]
import pycountry
except ModuleNotFoundError: # pragma: no cover
raise RuntimeError(
'The `country` module requires "pycountry" to be installed. You can install it with "pip install pycountry".'
Expand All @@ -24,49 +24,41 @@ class CountryInfo:
alpha3: str
numeric_code: str
short_name: str
# NOTE: Not all countries have an official name
official_name: str


@lru_cache()
@lru_cache
def _countries() -> list[CountryInfo]:
return [
CountryInfo(
alpha2=country.alpha_2,
alpha3=country.alpha_3,
numeric_code=country.numeric,
short_name=country.name,
official_name=getattr(country, 'official_name', ''),
)
for country in pycountry.countries
]


@lru_cache()
@lru_cache
def _index_by_alpha2() -> dict[str, CountryInfo]:
return {country.alpha2: country for country in _countries()}


@lru_cache()
@lru_cache
def _index_by_alpha3() -> dict[str, CountryInfo]:
return {country.alpha3: country for country in _countries()}


@lru_cache()
@lru_cache
def _index_by_numeric_code() -> dict[str, CountryInfo]:
return {country.numeric_code: country for country in _countries()}


@lru_cache()
@lru_cache
def _index_by_short_name() -> dict[str, CountryInfo]:
return {country.short_name: country for country in _countries()}


@lru_cache()
def _index_by_official_name() -> dict[str, CountryInfo]:
return {country.official_name: country for country in _countries() if country.official_name}


class CountryAlpha2(str):
"""CountryAlpha2 parses country codes in the [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
format.
Expand Down Expand Up @@ -123,12 +115,6 @@ def short_name(self) -> str:
"""The country short name."""
return _index_by_alpha2()[self].short_name

@property
def official_name(self) -> str:
"""The country official name."""
country = _index_by_alpha2()[self]
return country.official_name


class CountryAlpha3(str):
"""CountryAlpha3 parses country codes in the [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3)
Expand Down Expand Up @@ -187,12 +173,6 @@ def short_name(self) -> str:
"""The country short name."""
return _index_by_alpha3()[self].short_name

@property
def official_name(self) -> str:
"""The country official name."""
country = _index_by_alpha3()[self]
return country.official_name


class CountryNumericCode(str):
"""CountryNumericCode parses country codes in the
Expand Down Expand Up @@ -251,12 +231,6 @@ def short_name(self) -> str:
"""The country short name."""
return _index_by_numeric_code()[self].short_name

@property
def official_name(self) -> str:
"""The country official name."""
country = _index_by_numeric_code()[self]
return country.official_name


class CountryShortName(str):
"""CountryShortName parses country codes in the short name format.
Expand Down Expand Up @@ -305,63 +279,3 @@ def alpha3(self) -> str:
def numeric_code(self) -> str:
"""The country code in the [ISO 3166-1 numeric](https://en.wikipedia.org/wiki/ISO_3166-1_numeric) format."""
return _index_by_short_name()[self].numeric_code

@property
def official_name(self) -> str:
"""The country official name."""
country = _index_by_short_name()[self]
return country.official_name


class CountryOfficialName(str):
"""CountryOfficialName parses country codes in the official name format.
```py
from pydantic import BaseModel
from pydantic_extra_types.country import CountryOfficialName
class Product(BaseModel):
made_in: CountryOfficialName
product = Product(made_in="United States of America")
print(product)
#> made_in='United States of America'
```
"""

@classmethod
def _validate(cls, __input_value: str, _: core_schema.ValidationInfo) -> CountryOfficialName:
if __input_value not in _index_by_official_name():
raise PydanticCustomError('country_numeric_code', 'Invalid country official name')
return cls(__input_value)

@classmethod
def __get_pydantic_core_schema__(
cls, source: type[Any], handler: GetCoreSchemaHandler
) -> core_schema.AfterValidatorFunctionSchema:
return core_schema.with_info_after_validator_function(
cls._validate,
core_schema.str_schema(),
serialization=core_schema.to_string_ser_schema(),
)

@property
def alpha2(self) -> str:
"""The country code in the [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) format."""
return _index_by_official_name()[self].alpha2

@property
def alpha3(self) -> str:
"""The country code in the [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) format."""
return _index_by_official_name()[self].alpha3

@property
def numeric_code(self) -> str:
"""The country code in the [ISO 3166-1 numeric](https://en.wikipedia.org/wiki/ISO_3166-1_numeric) format."""
return _index_by_official_name()[self].numeric_code

@property
def short_name(self) -> str:
"""The country short name."""
return _index_by_official_name()[self].short_name
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ classifiers = [
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Intended Audience :: Developers',
'Intended Audience :: Information Technology',
'Intended Audience :: System Administrators',
Expand All @@ -37,7 +37,7 @@ classifiers = [
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Internet',
]
requires-python = '>=3.7'
requires-python = '>=3.8'
dependencies = [
'pydantic>=2.5.2',
]
Expand All @@ -46,7 +46,7 @@ dynamic = ['version']
[project.optional-dependencies]
all = [
'phonenumbers>=8,<9',
'pycountry>=22,<23',
'pycountry>=23,<24',
'python-ulid>=1,<2',
]

Expand Down
38 changes: 19 additions & 19 deletions requirements/linting.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,51 @@
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --output-file=requirements/linting.txt --resolver=backtracking requirements/linting.in
# pip-compile --no-emit-index-url --output-file=requirements/linting.txt requirements/linting.in
#
annotated-types==0.5.0
annotated-types==0.6.0
# via -r requirements/linting.in
black==23.3.0
black==23.12.1
# via -r requirements/linting.in
cfgv==3.3.1
cfgv==3.4.0
# via pre-commit
click==8.1.3
click==8.1.7
# via black
distlib==0.3.6
distlib==0.3.8
# via virtualenv
filelock==3.12.0
filelock==3.13.1
# via virtualenv
identify==2.5.24
identify==2.5.33
# via pre-commit
mypy==1.3.0
mypy==1.8.0
# via -r requirements/linting.in
mypy-extensions==1.0.0
# via
# black
# mypy
nodeenv==1.8.0
# via pre-commit
packaging==23.1
packaging==23.2
# via black
pathspec==0.11.1
pathspec==0.12.1
# via black
platformdirs==3.5.1
platformdirs==4.1.0
# via
# black
# virtualenv
pre-commit==3.3.2
pre-commit==3.6.0
# via -r requirements/linting.in
pyupgrade==3.4.0
pyupgrade==3.15.0
# via -r requirements/linting.in
pyyaml==6.0
pyyaml==6.0.1
# via pre-commit
ruff==0.0.270
ruff==0.1.11
# via -r requirements/linting.in
tokenize-rt==5.0.0
tokenize-rt==5.2.0
# via pyupgrade
typing-extensions==4.6.3
typing-extensions==4.9.0
# via mypy
virtualenv==20.23.0
virtualenv==20.25.0
# via pre-commit

# The following packages are considered to be unsafe in a requirements file:
Expand Down
14 changes: 7 additions & 7 deletions requirements/pyproject.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --extra=all --output-file=requirements/pyproject.txt --resolver=backtracking pyproject.toml
# pip-compile --extra=all --no-emit-index-url --output-file=requirements/pyproject.txt pyproject.toml
#
annotated-types==0.5.0
annotated-types==0.6.0
# via pydantic
phonenumbers==8.13.13
phonenumbers==8.13.27
# via pydantic-extra-types (pyproject.toml)
pycountry==22.3.5
pycountry==23.12.11
# via pydantic-extra-types (pyproject.toml)
pydantic==2.5.2
pydantic==2.5.3
# via pydantic-extra-types (pyproject.toml)
pydantic-core==2.14.5
pydantic-core==2.14.6
# via pydantic
python-ulid==1.1.0
# via pydantic-extra-types (pyproject.toml)
typing-extensions==4.6.3
typing-extensions==4.9.0
# via
# pydantic
# pydantic-core
Expand Down
28 changes: 14 additions & 14 deletions requirements/testing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,36 @@
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --output-file=requirements/testing.txt --resolver=backtracking requirements/testing.in
# pip-compile --no-emit-index-url --output-file=requirements/testing.txt requirements/testing.in
#
certifi==2023.5.7
certifi==2023.11.17
# via requests
charset-normalizer==3.1.0
charset-normalizer==3.3.2
# via requests
codecov==2.1.13
# via -r requirements/testing.in
coverage[toml]==7.2.7
coverage[toml]==7.4.0
# via
# -r requirements/testing.in
# codecov
# pytest-cov
dirty-equals==0.6.0
dirty-equals==0.7.1.post0
# via -r requirements/testing.in
idna==3.4
idna==3.6
# via requests
iniconfig==2.0.0
# via pytest
markdown-it-py==2.2.0
markdown-it-py==3.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
packaging==23.1
packaging==23.2
# via pytest
pluggy==1.0.0
pluggy==1.3.0
# via pytest
pygments==2.15.1
pygments==2.17.2
# via rich
pytest==7.3.1
pytest==7.4.4
# via
# -r requirements/testing.in
# pytest-cov
Expand All @@ -40,11 +40,11 @@ pytest-cov==4.1.0
# via -r requirements/testing.in
pytest-pretty==1.2.0
# via -r requirements/testing.in
pytz==2023.3
pytz==2023.3.post1
# via dirty-equals
requests==2.31.0
# via codecov
rich==13.4.1
rich==13.7.0
# via pytest-pretty
urllib3==2.0.2
urllib3==2.1.0
# via requests
Loading

0 comments on commit 5216db3

Please sign in to comment.