Skip to content

Commit

Permalink
Merge pull request #326 from jodal/py39
Browse files Browse the repository at this point in the history
Require Python 3.9
  • Loading branch information
jodal authored Oct 3, 2024
2 parents cf6d8f6 + 6ab0928 commit 165509b
Show file tree
Hide file tree
Showing 19 changed files with 54 additions and 51 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
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 }}
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
nodejs 21.1.0
poetry 1.8.3
python 3.12 3.11 3.10 3.9 3.8 3.13.0rc2
python 3.12 3.11 3.10 3.9 3.13.0rc2
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ see the [documentation](https://biip.readthedocs.io/).

## Installation

Biip requires Python 3.8 or newer.
Biip requires Python 3.9 or newer.

Biip is available from [PyPI](https://pypi.org/project/biip/):

Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ For details on how the barcode data is interpreted, please refer to the
Installation
============

Biip requires Python 3.8 or newer.
Biip requires Python 3.9 or newer.

Biip is available from `PyPI <https://pypi.org/project/biip/>`_:

Expand Down
2 changes: 1 addition & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

locations = ["src", "tests", "noxfile.py", "docs/conf.py", "scripts"]

supported_pythons = ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
supported_pythons = ["3.9", "3.10", "3.11", "3.12", "3.13"]
docs_python = "3.12"


Expand Down
9 changes: 5 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ classifiers = [
]

[tool.poetry.dependencies]
python = "^3.8.0"
python = "^3.9.0"
py-moneyed = { version = ">=0.8", optional = true }

[tool.poetry.extras]
Expand All @@ -33,7 +33,7 @@ py-moneyed = "^3.0"
types-beautifulsoup4 = "^4.12.0.6"

[tool.poetry.group.docs.dependencies]
sphinx = ">=7" # Requires Python 3.9+
sphinx = ">=7"
sphinx-rtd-theme = ">=2"
sphinx-autodoc-typehints = ">=2"

Expand All @@ -60,6 +60,7 @@ branch = true
source = ["biip"]

[tool.coverage.report]
exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:"]
fail_under = 100
show_missing = true

Expand All @@ -80,7 +81,7 @@ module = "biip.*"
disallow_untyped_defs = true

[tool.pyright]
pythonVersion = "3.8"
pythonVersion = "3.9"
venvPath = "."
venv = ".venv"
typeCheckingMode = "strict"
Expand All @@ -90,7 +91,7 @@ reportImportCycles = false
reportPrivateUsage = false

[tool.ruff]
target-version = "py38"
target-version = "py39"

[tool.ruff.lint]
select = ["ALL"]
Expand Down
7 changes: 3 additions & 4 deletions scripts/download_gs1_ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import dataclasses
import json
from typing import List

import httpx

Expand All @@ -23,9 +22,9 @@ def download(url: str) -> bytes:
return httpx.get(url, timeout=30).content


def parse(json_content: bytes) -> List[GS1ApplicationIdentifier]:
def parse(json_content: bytes) -> list[GS1ApplicationIdentifier]:
"""Parse the data from HTML to GS1ApplicationIdentifier objects."""
result: List[GS1ApplicationIdentifier] = []
result: list[GS1ApplicationIdentifier] = []

data = json.loads(json_content)

Expand Down Expand Up @@ -54,7 +53,7 @@ def _fix_pattern(value: str) -> str:
return value


def output(application_identifiers: List[GS1ApplicationIdentifier]) -> None:
def output(application_identifiers: list[GS1ApplicationIdentifier]) -> None:
"""Output the GS1ApplicationIdentifier objects as JSON to stdout."""
print(
json.dumps([dataclasses.asdict(ai) for ai in application_identifiers], indent=2)
Expand Down
4 changes: 2 additions & 2 deletions scripts/download_gs1_company_prefixes.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""Script to download and extract Company Prefix data from GS1."""

import json
from typing import Dict, Union
from typing import Union
from xml.etree import ElementTree # noqa: ICN001

import httpx

TrieNode = Union[Dict[str, "TrieNode"], int]
TrieNode = Union[dict[str, "TrieNode"], int]

COMPANY_PREFIX_URL = "https://www.gs1.org/docs/gcp_length/gcpprefixformatlist.xml"

Expand Down
9 changes: 4 additions & 5 deletions scripts/download_gs1_prefixes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import dataclasses
import json
from typing import List

import bs4
import httpx
Expand All @@ -15,7 +14,7 @@
def main() -> None:
"""The script's main function."""
html_content = download(PREFIX_URL)
prefixes: List[_GS1PrefixRange] = parse(html_content)
prefixes: list[_GS1PrefixRange] = parse(html_content)
output(prefixes)


Expand All @@ -24,9 +23,9 @@ def download(url: str) -> bytes:
return httpx.get(url, timeout=30).content


def parse(html_content: bytes) -> List[_GS1PrefixRange]:
def parse(html_content: bytes) -> list[_GS1PrefixRange]:
"""Parse the data from HTML to _GS1PrefixRange objects."""
result: List[_GS1PrefixRange] = []
result: list[_GS1PrefixRange] = []

page = bs4.BeautifulSoup(html_content, "html.parser")
datatable = page.find("table", {"class": ["table"]})
Expand Down Expand Up @@ -79,7 +78,7 @@ def parse(html_content: bytes) -> List[_GS1PrefixRange]:
return result # noqa: RET504


def output(prefixes: List[_GS1PrefixRange]) -> None:
def output(prefixes: list[_GS1PrefixRange]) -> None:
"""Output the _GS1PrefixRange objects as JSON to stdout."""
print(json.dumps([dataclasses.asdict(cp) for cp in prefixes], indent=2))

Expand Down
7 changes: 5 additions & 2 deletions src/biip/_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from dataclasses import dataclass
from typing import Callable, Iterable, List, Optional, Tuple
from typing import TYPE_CHECKING, Callable, Optional

from biip import ParseError
from biip.gs1 import DEFAULT_SEPARATOR_CHARS, GS1Message, GS1Symbology
Expand All @@ -12,6 +12,9 @@
from biip.symbology import SymbologyIdentifier
from biip.upc import Upc

if TYPE_CHECKING:
from collections.abc import Iterable


def parse(
value: str,
Expand Down Expand Up @@ -157,7 +160,7 @@ def _get_errors_list(self) -> str:
)


ParseQueue = List[Tuple["Parser", str]]
ParseQueue = list[tuple["Parser", str]]
Parser = Callable[[str, ParseConfig, ParseQueue, ParseResult], None]


Expand Down
4 changes: 1 addition & 3 deletions src/biip/gs1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,13 @@
date=None, datetime=None, decimal=None, money=None)
"""

from typing import Tuple

ASCII_GROUP_SEPARATOR = "\x1d"

#: The default separator character is <GS>, ASCII value 29.
#:
#: References:
#: GS1 General Specifications, section 7.8.3.
DEFAULT_SEPARATOR_CHARS: Tuple[str] = (ASCII_GROUP_SEPARATOR,)
DEFAULT_SEPARATOR_CHARS: tuple[str] = (ASCII_GROUP_SEPARATOR,)

# The following must be imported in this specific order.
# ruff: noqa: E402, I001
Expand Down
9 changes: 6 additions & 3 deletions src/biip/gs1/_element_strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
import re
from dataclasses import dataclass
from decimal import Decimal
from typing import Iterable, List, Optional, Tuple
from typing import TYPE_CHECKING, Optional

from biip import ParseError
from biip.gln import Gln
from biip.gs1 import DEFAULT_SEPARATOR_CHARS, GS1ApplicationIdentifier
from biip.gtin import Gtin, RcnRegion
from biip.sscc import Sscc

if TYPE_CHECKING:
from collections.abc import Iterable

try:
import moneyed # noqa: TCH002

Expand Down Expand Up @@ -56,7 +59,7 @@ class GS1ElementString:
value: str

#: List of pattern groups extracted from the Element String.
pattern_groups: List[str]
pattern_groups: list[str]

#: A GLN created from the element string, if the AI represents a GLN.
gln: Optional[Gln] = None
Expand Down Expand Up @@ -286,7 +289,7 @@ def as_hri(self) -> str:
return f"{self.ai}{self.value}"


def _parse_date_and_datetime(value: str) -> Tuple[dt.date, Optional[dt.datetime]]:
def _parse_date_and_datetime(value: str) -> tuple[dt.date, Optional[dt.datetime]]:
pairs = [value[i : i + 2] for i in range(0, len(value), 2)]

year = int(pairs[0])
Expand Down
18 changes: 10 additions & 8 deletions src/biip/gs1/_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import re
from dataclasses import dataclass
from itertools import chain
from typing import TYPE_CHECKING, Iterable, List, Optional, Tuple, Union
from typing import TYPE_CHECKING, Optional, Union

from biip import ParseError
from biip.gs1 import (
Expand All @@ -16,7 +16,9 @@
)
from biip.gs1._application_identifiers import _GS1_APPLICATION_IDENTIFIERS

if TYPE_CHECKING: # pragma: no cover
if TYPE_CHECKING:
from collections.abc import Iterable

from biip.gtin import RcnRegion


Expand All @@ -34,7 +36,7 @@ class GS1Message:
value: str

#: List of Element Strings found in the message.
element_strings: List[GS1ElementString]
element_strings: list[GS1ElementString]

@classmethod
def parse(
Expand Down Expand Up @@ -70,7 +72,7 @@ def parse(
ParseError: If the parsing fails.
"""
value = value.strip()
element_strings: List[GS1ElementString] = []
element_strings: list[GS1ElementString] = []
rest = value[:]

while rest:
Expand Down Expand Up @@ -124,15 +126,15 @@ def parse_hri(
raise ParseError(msg)

pattern = r"\((\d+)\)(\w+)"
matches: List[Tuple[str, str]] = re.findall(pattern, value)
matches: list[tuple[str, str]] = re.findall(pattern, value)
if not matches:
msg = (
f"Could not find any GS1 Application Identifiers in {value!r}. "
"Expected format: '(AI)DATA(AI)DATA'."
)
raise ParseError(msg)

pairs: List[Tuple[GS1ApplicationIdentifier, str]] = []
pairs: list[tuple[GS1ApplicationIdentifier, str]] = []
for ai_number, ai_data in matches:
if ai_number not in _GS1_APPLICATION_IDENTIFIERS:
msg = f"Unknown GS1 Application Identifier {ai_number!r} in {value!r}."
Expand Down Expand Up @@ -171,7 +173,7 @@ def filter(
*,
ai: Optional[Union[str, GS1ApplicationIdentifier]] = None,
data_title: Optional[str] = None,
) -> List[GS1ElementString]:
) -> list[GS1ElementString]:
"""Filter Element Strings by AI or data title.
Args:
Expand All @@ -186,7 +188,7 @@ def filter(
if isinstance(ai, GS1ApplicationIdentifier):
ai = ai.ai

result: List[GS1ElementString] = []
result: list[GS1ElementString] = []

for element_string in self.element_strings:
ai_match = ai is not None and element_string.ai.ai.startswith(ai)
Expand Down
4 changes: 2 additions & 2 deletions src/biip/gs1/_prefixes.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
import lzma
import pathlib
from dataclasses import dataclass
from typing import Dict, Optional, Union
from typing import Optional, Union

from biip import ParseError

_TrieNode = Union[Dict[str, "_TrieNode"], int]
_TrieNode = Union[dict[str, "_TrieNode"], int]


@dataclass(frozen=True)
Expand Down
5 changes: 2 additions & 3 deletions src/biip/gs1/_symbology.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from __future__ import annotations

from enum import Enum
from typing import Set


class GS1Symbology(Enum):
Expand Down Expand Up @@ -54,7 +53,7 @@ class GS1Symbology(Enum):
GS1_DOTCODE = "J1"

@classmethod
def with_ai_element_strings(cls) -> Set[GS1Symbology]:
def with_ai_element_strings(cls) -> set[GS1Symbology]:
"""Symbologies that may contain AI Element Strings."""
return {
cls.GS1_128,
Expand All @@ -65,7 +64,7 @@ def with_ai_element_strings(cls) -> Set[GS1Symbology]:
}

@classmethod
def with_gtin(cls) -> Set[GS1Symbology]:
def with_gtin(cls) -> set[GS1Symbology]:
"""Symbologies that may contain GTINs."""
return {cls.EAN_13, cls.EAN_13_WITH_ADD_ON, cls.EAN_8, cls.ITF_14}

Expand Down
4 changes: 2 additions & 2 deletions src/biip/gtin/_gtin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from dataclasses import dataclass
from typing import Optional, Type, Union
from typing import Optional, Union

from biip import EncodeError, ParseError
from biip.gs1 import GS1CompanyPrefix, GS1Prefix
Expand Down Expand Up @@ -121,7 +121,7 @@ def parse(
)
raise ParseError(msg)

gtin_type: Type[Union[Gtin, Rcn]]
gtin_type: type[Union[Gtin, Rcn]]
if (
gtin_format <= GtinFormat.GTIN_13
and prefix is not None
Expand Down
4 changes: 2 additions & 2 deletions src/biip/gtin/_rcn.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from dataclasses import dataclass, field
from decimal import Decimal
from enum import Enum
from typing import Dict, Optional, Union
from typing import Optional, Union

from biip import EncodeError, ParseError
from biip.gs1 import checksums
Expand Down Expand Up @@ -244,7 +244,7 @@ def without_variable_measure(self, rcn: Rcn) -> Gtin:
return Gtin.parse(gtin, rcn_region=rcn.region)


_RCN_RULES: Dict[RcnRegion, Dict[str, _Strategy]] = {
_RCN_RULES: dict[RcnRegion, dict[str, _Strategy]] = {
RcnRegion.DENMARK: {
# References:
# https://www.gs1.dk/om-gs1/overblik-over-gs1-standarder/gtin-13-pris
Expand Down
Loading

0 comments on commit 165509b

Please sign in to comment.