Skip to content

Commit

Permalink
Merge pull request #195 from khaeru/python-3.13
Browse files Browse the repository at this point in the history
Confirm support for Python 3.13 and drop 3.8
  • Loading branch information
khaeru authored Oct 15, 2024
2 parents 5256723 + 6f113ca commit e80f9e6
Show file tree
Hide file tree
Showing 40 changed files with 208 additions and 203 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ jobs:
- ubuntu-latest
- windows-latest
python-version:
- "3.8" # Earliest supported version
- "3.9"
- "3.9" # Earliest supported version
- "3.10"
- "3.11"
- "3.12" # Latest supported version
- "3.12"
- "3.13" # Latest supported version
# commented: only enable once next Python version enters RC
# - "3.13.0-rc.1" # Development version
# - "3.14.0-rc.1" # Development version

fail-fast: false

Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.11.1
rev: v1.12.0
hooks:
- id: mypy
additional_dependencies:
Expand All @@ -15,7 +15,7 @@ repos:
- types-requests
args: []
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.0
rev: v0.6.9
hooks:
- id: ruff
- id: ruff-format
Expand Down
2 changes: 1 addition & 1 deletion doc/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Installation
Dependencies
============

:mod:`sdmx` is a pure `Python <https://python.org>`_ package requiring Python 3.8 or higher, which can be installed:
:mod:`sdmx` is a pure `Python <https://python.org>`_ package requiring Python 3.9 or higher, which can be installed:

- from `the Python website <https://www.python.org/downloads/>`_, or
- using a scientific Python distribution that includes other packages useful for data analysis, such as
Expand Down
8 changes: 6 additions & 2 deletions doc/whatsnew.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
What's new?
***********

.. Next release
.. ============
Next release
============

- Python 3.13 (`released 2024-10-07 <https://www.python.org/downloads/release/python-3130/>`_) is fully supported (:pull:`195`).
- Python 3.8 support is dropped, as `it has reached end-of-life <https://peps.python.org/pep-0569/#lifespan>`__ (:pull:`195`).
:mod:`sdmx` requires Python 3.9 or later.

v2.17.0 (2024-09-03)
====================
Expand Down
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ classifiers = [
"Operating System :: OS Independent",
"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",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Information Analysis",
]
requires-python = ">=3.8"
requires-python = ">=3.9"
dependencies = [
"lxml >= 3.6",
"pandas >= 1.0",
Expand All @@ -41,7 +41,6 @@ cache = ["requests-cache"]
docs = ["IPython", "sphinx >=4", "sphinx-book-theme"]
tests = [
"Jinja2",
"pyarrow", # Suppress a warning from pandas >=2.2, <3.0
"pytest >= 5",
"pytest-cov",
"pytest-xdist",
Expand Down
6 changes: 3 additions & 3 deletions sdmx/client.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
from functools import partial
from typing import IO, TYPE_CHECKING, Any, Dict, Optional, Union
from typing import IO, TYPE_CHECKING, Any, Optional, Union
from warnings import warn

import requests
Expand Down Expand Up @@ -56,7 +56,7 @@ class Client:
"""

cache: Dict[str, "sdmx.message.Message"] = {}
cache: dict[str, "sdmx.message.Message"] = {}

#: :class:`.source.Source` for requests sent from the instance.
source: "sdmx.source.Source"
Expand All @@ -65,7 +65,7 @@ class Client:
session: requests.Session

# Stored keyword arguments "allow_redirects" and "timeout" for pre-requests.
_send_kwargs: Dict[str, Any] = {}
_send_kwargs: dict[str, Any] = {}

def __init__(self, source=None, log_level=None, **session_opts):
try:
Expand Down
6 changes: 3 additions & 3 deletions sdmx/dictlike.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import logging
import typing
from dataclasses import fields
from typing import Generic, Tuple, TypeVar, Union, get_args, get_origin
from typing import Generic, TypeVar, Union, get_args, get_origin

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -67,7 +67,7 @@ def update(self, other):
def __hash__(cls):
pass

def _validate_entry(self, kv: Tuple):
def _validate_entry(self, kv: tuple):
"""Validate one `key`/`value` pair."""
key, value = kv
try:
Expand Down Expand Up @@ -147,7 +147,7 @@ def _get_field_types(self, obj):
self._field = next(filter(lambda f: f.name == self._name[1:], fields(obj)))
# The type is DictLike[KeyType, ValueType]; retrieve those arguments
kt, vt = get_args(self._field.type)
# Store. If ValueType is a generic, e.g. List[int], store only List.
# Store. If ValueType is a generic, e.g. list[int], store only List.
self._types = (kt, get_origin(vt) or vt)

def __get__(self, obj, type) -> DictLike[KT, VT]:
Expand Down
2 changes: 1 addition & 1 deletion sdmx/experimental.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def add_obs(self, observations, series_key=None):

@property
def obs(self):
# In model.DataSet, .obs is typed as List[Observation].
# In model.DataSet, .obs is typed as list[Observation].
# Here, the Observations are generated on request.
for key, data in self._data.iterrows():
yield self._make_obs(key, data)
Expand Down
4 changes: 2 additions & 2 deletions sdmx/format/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from dataclasses import InitVar, dataclass, field
from enum import Enum, IntFlag
from functools import lru_cache
from typing import List, Literal, Optional, Union
from typing import Literal, Optional, Union

from sdmx.util import parse_content_type

Expand Down Expand Up @@ -141,7 +141,7 @@ def is_time_series(self) -> bool:
]


def list_media_types(**filters) -> List[MediaType]:
def list_media_types(**filters) -> list[MediaType]:
"""Return the string for each item in :data:`MEDIA_TYPES` matching `filters`."""
result = []
for mt in MEDIA_TYPES:
Expand Down
8 changes: 4 additions & 4 deletions sdmx/format/xml/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from operator import itemgetter
from pathlib import Path
from shutil import copytree
from typing import IO, Iterable, List, Mapping, Optional, Tuple, Union
from typing import IO, Iterable, Mapping, Optional, Union

from lxml import etree
from lxml.etree import QName
Expand Down Expand Up @@ -221,7 +221,7 @@ def _extracted_zipball(version: Version) -> Path:

def _handle_validate_args(
schema_dir: Optional[Path], version: Union[str, Version]
) -> Tuple[Path, Version]:
) -> tuple[Path, Version]:
"""Handle arguments for :func:`.install_schemas` and :func:`.validate_xml`."""
import platformdirs

Expand Down Expand Up @@ -274,9 +274,9 @@ def install_schemas(

class XMLFormat:
NS: Mapping[str, Optional[str]]
_class_tag: List
_class_tag: list

def __init__(self, model, base_ns: str, class_tag: Iterable[Tuple[str, str]]):
def __init__(self, model, base_ns: str, class_tag: Iterable[tuple[str, str]]):
from sdmx import message # noqa: F401

self.base_ns = base_ns
Expand Down
19 changes: 8 additions & 11 deletions sdmx/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@
from typing import (
TYPE_CHECKING,
Generator,
List,
Optional,
Text,
Tuple,
Type,
Union,
get_args,
)
Expand All @@ -42,7 +39,7 @@
log = logging.getLogger(__name__)


def _summarize(obj, include: Optional[List[str]] = None):
def _summarize(obj, include: Optional[list[str]] = None):
"""Helper method for __repr__ on Header and Message (sub)classes."""
import requests

Expand Down Expand Up @@ -123,7 +120,7 @@ class Footer:
#:
severity: Optional[str] = None
#: The body text of the Footer contains zero or more blocks of text.
text: List[model.InternationalString] = field(default_factory=list)
text: list[model.InternationalString] = field(default_factory=list)
#:
code: Optional[int] = None

Expand Down Expand Up @@ -315,7 +312,7 @@ def get(
# separator characters
urn_expr = re.compile(rf"[=:]{re.escape(id_)}")

candidates: List[model.IdentifiableArtefact] = []
candidates: list[model.IdentifiableArtefact] = []
for key, obj in chain(*[c.items() for c in self._collections]):
if id_ in (key, obj.id) or urn_expr.search(obj.urn or ""):
candidates.append(obj)
Expand All @@ -325,7 +322,7 @@ def get(

return candidates[0] if len(candidates) == 1 else None

def iter_collections(self) -> Generator[Tuple[str, type], None, None]:
def iter_collections(self) -> Generator[tuple[str, type], None, None]:
"""Iterate over collections."""
for f in direct_fields(self.__class__):
yield f.name, get_args(f.type)[1]
Expand Down Expand Up @@ -380,15 +377,15 @@ class DataMessage(Message):
"""

#: :class:`list` of :class:`.DataSet`.
data: List[model.BaseDataSet] = field(default_factory=list)
data: list[model.BaseDataSet] = field(default_factory=list)
#: :class:`.DataflowDefinition` that contains the data.
dataflow: Optional[model.BaseDataflow] = None
#: The "dimension at observation level".
observation_dimension: Optional[
Union[
model._AllDimensions,
model.DimensionComponent,
List[model.DimensionComponent],
list[model.DimensionComponent],
]
] = None

Expand All @@ -407,7 +404,7 @@ def structure(self):
return self.dataflow.structure

@property
def structure_type(self) -> Type[common.Structure]:
def structure_type(self) -> type[common.Structure]:
""":class:`.Structure` subtype describing the contained (meta)data."""
return {
Version["2.1"]: v21.DataStructureDefinition,
Expand Down Expand Up @@ -522,7 +519,7 @@ class MetadataMessage(DataMessage):
"""SDMX Metadata Message."""

@property
def structure_type(self) -> Type[common.Structure]:
def structure_type(self) -> type[common.Structure]:
return {
Version["2.1"]: v21.MetadataStructureDefinition,
Version["3.0.0"]: v30.MetadataStructureDefinition,
Expand Down
2 changes: 1 addition & 1 deletion sdmx/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from . import common, v21

WARNED = set()
WARNED: set[str] = set()


def __dir__():
Expand Down
Loading

0 comments on commit e80f9e6

Please sign in to comment.