diff --git a/docs/contributor-guide/contributing.md b/docs/contributor-guide/contributing.md index 32424d537..cdded9e3b 100644 --- a/docs/contributor-guide/contributing.md +++ b/docs/contributor-guide/contributing.md @@ -178,6 +178,14 @@ merge" button in GitHub 🥳. Your PR is now merged into kloppy! We'll shout out your contribution in the release notes. +### Optional dependencies + +Optional dependencies (e.g. `polars`) should be imported with the helper `kloppy._utils.optional.import_optional_dependency`. This ensures a consistent error message when the dependency is not met. + +All methods using an optional dependency should include a test asserting that an `ImportError` is raised when the optional dependency is not found. This test should be skipped if the library is present. + +All optional dependencies should be documented in the [Optional dependencies](../user-guide/installation/index.md#optional-dependencies) section of the user guide and the minimum required version should be set in the `kloppy._utils.VERSIONS` dict. + ## Documentation contributions Contributing to the documentation benefits everyone who uses kloppy. If diff --git a/docs/user-guide/installation/index.md b/docs/user-guide/installation/index.md index 06d658718..d3e214c16 100644 --- a/docs/user-guide/installation/index.md +++ b/docs/user-guide/installation/index.md @@ -4,7 +4,7 @@ Before you can use kloppy, you'll need to get it installed. This guide will guid ## Install Python -Being a Python library, kloppy requires Python. Currently, kloppy supports Python version 3.9 — 3.12. Get the latest version of Python at [python.org](https://www.python.org/downloads/) or with your operating system's package manager. +Being a Python library, kloppy requires Python. Currently, kloppy supports Python version 3.9 — 3.13. Get the latest version of Python at [python.org](https://www.python.org/downloads/) or with your operating system's package manager. You can verify that Python is installed by typing `python` from your shell; you should see something like: @@ -29,6 +29,7 @@ $ python -m pip install kloppy You might have to install pip first. The easiest method is to use the [standalone pip installer](https://pip.pypa.io/en/latest/installing/#installing-with-get-pip-py). + ### Installing the development version Kloppy is actively developed on GitHub, where the code is [always available](https://github.com/PySport/kloppy). You can easily install the development version with: @@ -64,3 +65,29 @@ To verify that kloppy can be seen by Python, type `python` from your shell. Then >>> import kloppy >>> print(kloppy.__version__) ``` + +## Optional dependencies + +Kloppy has a few optional dependencies that are only required for specific functionality. For example, loading datasets directly from an S3 bucket requires `s3fs`. If an optional dependency is missing, kloppy raises an `ImportError` when the corresponding functionality is used. + +The available optional dependencies are: + +- `polars` (extra: `polars`): required to export datasets to Polars DataFrames with [`to_df()`][kloppy.domain.Dataset.to_df]. +- `pandas` (extra: `pandas`): required to export datasets to pandas DataFrames with [`to_df()`][kloppy.domain.Dataset.to_df]. +- `pyarrow` (extra: `pyarrow`): required to export datasets to pandas DataFrames backed by PyArrow with [`to_df()`][kloppy.domain.Dataset.to_df]. +- `networkx` (extra: `query`): used by the `event_pattern_matching` module for sequence and pattern queries. +- `s3fs` (extra: `s3`): required to load datasets directly from Amazon S3 buckets. + +With pip, you can install a subset of these dependencies with: + +```console +$ python -m pip install "kloppy[pandas,s3]" +``` + +Or, alternatively, to install all optional dependencies: + +```console +$ python -m pip install "kloppy[all]" +``` + + diff --git a/kloppy/_providers/metrica.py b/kloppy/_providers/metrica.py index d103f9262..4d8d7b3de 100644 --- a/kloppy/_providers/metrica.py +++ b/kloppy/_providers/metrica.py @@ -1,5 +1,6 @@ from typing import Optional, Union +from kloppy._utils import github_resolve_raw_data_url from kloppy.config import get_config from kloppy.domain import EventDataset, EventFactory, TrackingDataset from kloppy.exceptions import KloppyError @@ -16,7 +17,6 @@ MetricaEPTSTrackingDataInputs, ) from kloppy.io import FileLike, open_as_file -from kloppy.utils import github_resolve_raw_data_url def load_tracking_csv( diff --git a/kloppy/_providers/skillcorner.py b/kloppy/_providers/skillcorner.py index 97a6003e2..8ec2e05e0 100644 --- a/kloppy/_providers/skillcorner.py +++ b/kloppy/_providers/skillcorner.py @@ -1,6 +1,7 @@ import json from typing import Optional, Union +from kloppy._utils import github_resolve_raw_data_url from kloppy.domain import TrackingDataset from kloppy.exceptions import DeserializationError from kloppy.infra.serializers.tracking.skillcorner import ( @@ -8,7 +9,6 @@ SkillCornerInputs, ) from kloppy.io import FileLike, open_as_file -from kloppy.utils import github_resolve_raw_data_url def load( diff --git a/kloppy/_providers/sportec.py b/kloppy/_providers/sportec.py index 9f232cf39..45bd975ef 100644 --- a/kloppy/_providers/sportec.py +++ b/kloppy/_providers/sportec.py @@ -1,5 +1,6 @@ from typing import Optional +from kloppy._utils import deprecated from kloppy.config import get_config from kloppy.domain import EventDataset, EventFactory, TrackingDataset from kloppy.infra.serializers.event.sportec import ( @@ -11,7 +12,6 @@ SportecTrackingDataInputs, ) from kloppy.io import FileLike, open_as_file -from kloppy.utils import deprecated def load_event( diff --git a/kloppy/_providers/statsbomb.py b/kloppy/_providers/statsbomb.py index c2845d92e..7a78b5887 100644 --- a/kloppy/_providers/statsbomb.py +++ b/kloppy/_providers/statsbomb.py @@ -1,6 +1,7 @@ from typing import Optional, Union import warnings +from kloppy._utils import github_resolve_raw_data_url from kloppy.config import get_config from kloppy.domain import EventDataset, EventFactory from kloppy.domain.models.statsbomb.event import StatsBombEventFactory @@ -9,7 +10,6 @@ StatsBombInputs, ) from kloppy.io import FileLike, Source, open_as_file -from kloppy.utils import github_resolve_raw_data_url def load( diff --git a/kloppy/_providers/statsperform.py b/kloppy/_providers/statsperform.py index b23f17047..66ed712ef 100644 --- a/kloppy/_providers/statsperform.py +++ b/kloppy/_providers/statsperform.py @@ -1,5 +1,6 @@ from typing import Optional +from kloppy._utils import deprecated from kloppy.config import get_config from kloppy.domain import EventDataset, EventFactory, Provider, TrackingDataset from kloppy.infra.serializers.event.statsperform import ( @@ -15,7 +16,6 @@ StatsPerformInputs as StatsPerformTrackingInputs, ) from kloppy.io import FileLike, open_as_file -from kloppy.utils import deprecated @deprecated("statsperform.load_tracking should be used") diff --git a/kloppy/_providers/wyscout.py b/kloppy/_providers/wyscout.py index af4b19021..27e62d8c4 100644 --- a/kloppy/_providers/wyscout.py +++ b/kloppy/_providers/wyscout.py @@ -1,6 +1,7 @@ import json from typing import Optional, Union +from kloppy._utils import github_resolve_raw_data_url from kloppy.config import get_config from kloppy.domain import EventDataset, EventFactory from kloppy.infra.serializers.event.wyscout import ( @@ -9,7 +10,6 @@ WyscoutInputs, ) from kloppy.io import FileLike, open_as_file -from kloppy.utils import github_resolve_raw_data_url def load( diff --git a/kloppy/_utils/__init__.py b/kloppy/_utils/__init__.py new file mode 100644 index 000000000..08400baf7 --- /dev/null +++ b/kloppy/_utils/__init__.py @@ -0,0 +1,9 @@ +from .deprecation import ( + DeprecatedEnumValue, + deprecated, +) +from .docstrings import docstring_inherit_attributes +from .io import Readable, github_resolve_raw_data_url, to_file_object +from .logging import performance_logging +from .optional import import_optional_dependency +from .strings import remove_suffix, to_snake_case diff --git a/kloppy/_utils/deprecation.py b/kloppy/_utils/deprecation.py new file mode 100644 index 000000000..8c0897fb6 --- /dev/null +++ b/kloppy/_utils/deprecation.py @@ -0,0 +1,73 @@ +import functools +import inspect +import warnings + +string_types = (bytes, str) + + +def deprecated(reason): + """ + This is a decorator which can be used to mark functions + as deprecated. It will result in a warning being emitted + when the function is used. + """ + + if isinstance(reason, string_types): + + def decorator(func1): + if inspect.isclass(func1): + fmt1 = "Call to deprecated class {name} ({reason})." + else: + fmt1 = "Call to deprecated function {name} ({reason})." + + @functools.wraps(func1) + def new_func1(*args, **kwargs): + warnings.simplefilter("always", DeprecationWarning) + warnings.warn( + fmt1.format(name=func1.__name__, reason=reason), + category=DeprecationWarning, + stacklevel=2, + ) + warnings.simplefilter("default", DeprecationWarning) + return func1(*args, **kwargs) + + return new_func1 + + return decorator + + elif inspect.isclass(reason) or inspect.isfunction(reason): + func2 = reason + + if inspect.isclass(func2): + fmt2 = "Call to deprecated class {name}." + else: + fmt2 = "Call to deprecated function {name}." + + @functools.wraps(func2) + def new_func2(*args, **kwargs): + warnings.simplefilter("always", DeprecationWarning) + warnings.warn( + fmt2.format(name=func2.__name__), + category=DeprecationWarning, + stacklevel=2, + ) + warnings.simplefilter("default", DeprecationWarning) + return func2(*args, **kwargs) + + return new_func2 + + else: + raise TypeError(repr(type(reason))) + + +class DeprecatedEnumValue: + def __init__(self, value): + self.value = value + + def __get__(self, instance, owner): + warnings.warn( + f"{owner.__name__} is deprecated. Use GoalkeeperActionType instead.", + DeprecationWarning, + stacklevel=2, + ) + return self.value diff --git a/kloppy/_utils/docstrings.py b/kloppy/_utils/docstrings.py new file mode 100644 index 000000000..4cf69f2ee --- /dev/null +++ b/kloppy/_utils/docstrings.py @@ -0,0 +1,26 @@ +def docstring_inherit_attributes(parent): + def inherit(obj): + other_docs, attribute_docs = obj.__doc__.split("Attributes:\n") + + own_attributes = [ + attribute.strip() + for attribute in attribute_docs.strip().split("\n") + ] + + parent_attributes = [ + attribute.strip() + for attribute in parent.__doc__.split("Attributes:\n")[-1] + .strip() + .split("\n") + ] + obj.__doc__ = ( + other_docs + + "Attributes:\n " + + "\n ".join(parent_attributes) + + "\n " + + "\n ".join(own_attributes) + + "\n" + ) + return obj + + return inherit diff --git a/kloppy/_utils/io.py b/kloppy/_utils/io.py new file mode 100644 index 000000000..1a721f516 --- /dev/null +++ b/kloppy/_utils/io.py @@ -0,0 +1,57 @@ +from io import BytesIO +from typing import BinaryIO, Union +from urllib.parse import quote +from urllib.request import Request, urlopen + +Readable = Union[bytes, BinaryIO] + + +def to_file_object(s: Readable) -> BinaryIO: + if isinstance(s, bytes): + return BytesIO(s) + return s + + +def github_resolve_raw_data_url(repository: str, branch: str, file: str) -> str: + """ + Resolve a GitHub repository file to its actual raw data URL. + + GitHub serves files differently depending on their size: + - Small files are redirected to raw.githubusercontent.com + - Large files (Git LFS) are redirected to media.githubusercontent.com + + This function follows the redirect and returns the final URL. + + Args: + repository: The repository in the format "owner/repo" (e.g., "metrica-sports/sample-data") + branch: The branch name (e.g., "master", "main") + file: The file path within the repository (e.g., "data/file.csv") + + Returns: + The resolved raw data URL + + Examples: + >>> github_resolve_raw_data_url( + ... repository="metrica-sports/sample-data", + ... branch="master", + ... file="data/Sample_Game_1/Sample_Game_1_RawTrackingData_Home_Team.csv" + ... ) + 'https://raw.githubusercontent.com/metrica-sports/sample-data/master/data/Sample_Game_1/Sample_Game_1_RawTrackingData_Home_Team.csv' + """ + # Encode the file path properly to handle spaces and special characters + encoded_file = "/".join(quote(part, safe="") for part in file.split("/")) + + # Construct the GitHub raw URL + # This URL will redirect to either raw.githubusercontent.com or media.githubusercontent.com + github_url = f"https://github.com/{repository}/raw/refs/heads/{branch}/{encoded_file}" + + # Make a HEAD request to follow redirects and get the final URL + req = Request(github_url, method="HEAD") + try: + with urlopen(req) as response: + # The final URL after following redirects + return response.url + except Exception: + # If there's an error, fall back to the standard raw.githubusercontent.com URL + # This ensures backwards compatibility + return f"https://raw.githubusercontent.com/{repository}/{branch}/{encoded_file}" diff --git a/kloppy/_utils/logging.py b/kloppy/_utils/logging.py new file mode 100644 index 000000000..65b9cf2c7 --- /dev/null +++ b/kloppy/_utils/logging.py @@ -0,0 +1,31 @@ +from contextlib import contextmanager +from logging import Logger +import time +from typing import Optional + + +@contextmanager +def performance_logging( + description: str, + counter: Optional[int] = None, + logger: Optional[Logger] = None, +): + start = time.time() + try: + yield + finally: + took = (time.time() - start) * 1000 + extra = "" + if counter is not None: + extra = f" ({counter / took * 1000:.1f}items/sec)" + + unit = "ms" + if took < 0.1: + took *= 1000 + unit = "us" + + msg = f"{description} took: {took:.2f}{unit} {extra}" + if logger: + logger.info(msg) + else: + print(msg) diff --git a/kloppy/_utils/optional.py b/kloppy/_utils/optional.py new file mode 100644 index 000000000..997146258 --- /dev/null +++ b/kloppy/_utils/optional.py @@ -0,0 +1,125 @@ +import importlib +import sys +import types +from typing import Optional +import warnings + +VERSIONS = { + "networkx": "2.4", + "pandas": "2.0.3", + "polars": "0.16.6", + "pyarrow": "17.0.0", +} + +# Mapping of import module names to PyPI/Conda package names when they differ (e.g., "sklearn": "scikit-learn") +INSTALL_MAPPING = {} + + +def _get_version(module: types.ModuleType) -> str: + """Get the version string from a module. + + Args: + module (types.ModuleType): The module to check for a version. + + Returns: + str: The version string of the module. + + Raises: + ImportError: If the version cannot be determined. + """ + version = getattr(module, "__version__", None) + if version is None: + # xlrd uses a capitalized attribute name + version = getattr(module, "__VERSION__", None) + + if version is None: + raise ImportError(f"Can't determine version for {module.__name__}") + return version + + +def import_optional_dependency( + name: str, + extra: str = "", + raise_on_missing: bool = True, + on_version: str = "raise", + min_version: Optional[str] = None, +): + """Import an optional dependency. + + By default, if a dependency is missing an ImportError with a nice + message will be raised. If a dependency is present, but too old, + we raise. + + Args: + name (str): The module name. + extra (str, optional): Additional text to include in the ImportError message. + Defaults to "". + raise_on_missing (bool, optional): Whether to raise if the optional dependency + is not found. When False and the module is not present, None is returned. + Defaults to True. + on_version (str, optional): What to do when a dependency's version is too old. + - 'raise': Raise an ImportError. + - 'warn': Warn that the version is too old. Returns None. + - 'ignore': Return the module, even if the version is too old. + Defaults to "raise". + min_version (str, optional): Specify a minimum version that is different from + the global kloppy minimum version required. Defaults to None. + + Returns: + Optional[types.ModuleType]: The imported module, when found and the version + is correct. None is returned when the package is not found and + `raise_on_missing` is False, or when the package's version is too old and + `on_version` is 'warn'. + """ + + package_name = INSTALL_MAPPING.get(name) + install_name = package_name if package_name is not None else name + + msg = ( + f"Missing optional dependency '{install_name}'. {extra} " + f"Use pip or conda to install {install_name}." + ) + try: + module = importlib.import_module(name) + except ImportError: + if raise_on_missing: + raise ImportError(msg) from None + else: + return None + + # Handle submodules: if we have submodule, grab parent module from sys.modules + parent = name.split(".")[0] + if parent != name: + install_name = parent + module_to_get = sys.modules[install_name] + else: + module_to_get = module + minimum_version = ( + min_version if min_version is not None else VERSIONS.get(parent) + ) + if minimum_version: + version = _get_version(module_to_get) + + try: + from packaging.version import parse as parse_version + except ImportError: + try: + from distutils.version import LooseVersion as parse_version + except ImportError: + + def parse_version(v): + return tuple(map(int, (v.split(".") + ["0", "0"])[:3])) + + if parse_version(version) < parse_version(minimum_version): + assert on_version in {"warn", "raise", "ignore"} + msg = ( + f"Kloppy requires version '{minimum_version}' or newer of '{parent}' " + f"(version '{version}' currently installed)." + ) + if on_version == "warn": + warnings.warn(msg, UserWarning) + return None + elif on_version == "raise": + raise ImportError(msg) + + return module diff --git a/kloppy/_utils/strings.py b/kloppy/_utils/strings.py new file mode 100644 index 000000000..81a5731e5 --- /dev/null +++ b/kloppy/_utils/strings.py @@ -0,0 +1,45 @@ +import re + +_first_cap_re = re.compile("(.)([A-Z][a-z0-9]+)") +_all_cap_re = re.compile("([a-z0-9])([A-Z])") + + +def to_snake_case(string: str) -> str: + """Convert a string to snake_case. + + Args: + string (str): The string to convert. + + Returns: + str: The converted snake_case string. + + Examples: + >>> to_snake_case("CamelCase") + 'camel_case' + >>> to_snake_case("camelCase") + 'camel_case' + >>> to_snake_case("Space separated") + 'space_separated' + >>> to_snake_case("Hyphen-separated") + 'hyphen_separated' + """ + string = re.sub(r"[\s\-]+", "_", string.strip()) + s1 = _first_cap_re.sub(r"\1_\2", string) + s2 = _all_cap_re.sub(r"\1_\2", s1).lower() + return re.sub(r"_+", "_", s2) + + +def remove_suffix(string: str, suffix: str) -> str: + """Remove a suffix from a string if it is present. + + Args: + string (str): The original string. + suffix (str): The suffix to remove. + + Returns: + str: The string with the suffix removed if it was present, otherwise the original string. + """ + if string[-len(suffix) :] == suffix: + return string[: -len(suffix)] + else: + return string diff --git a/kloppy/_utils/testing.py b/kloppy/_utils/testing.py new file mode 100644 index 000000000..757ced83a --- /dev/null +++ b/kloppy/_utils/testing.py @@ -0,0 +1,47 @@ +from typing import Optional + +import pytest + +from kloppy._utils.optional import import_optional_dependency + + +def skip_if_no( + package: str, min_version: Optional[str] = None +) -> pytest.MarkDecorator: + """ + Generic function to help skip tests when required packages are not + present on the testing system. + + This function returns a pytest mark with a skip condition that will be + evaluated during test collection. An attempt will be made to import the + specified ``package`` and optionally ensure it meets the ``min_version``. + + The mark can be used as either a decorator for a test class or to be + applied to parameters in pytest.mark.parametrize calls or parametrized + fixtures. Use pytest.importorskip if an imported module is later needed + or for test functions. + + If the import and version check are unsuccessful, then the test function + (or test case when used in conjunction with parametrization) will be + skipped. + + Args: + package (str): The name of the required package. + min_version (Optional[str]): Optional minimum version of the package. Defaults to None. + + Returns: + pytest.MarkDecorator: A pytest.mark.skipif to use as either a test + decorator or a parametrization mark. + """ + msg = f"Could not import '{package}'" + if min_version: + msg += f" satisfying a min_version of {min_version}" + + return pytest.mark.skipif( + not bool( + import_optional_dependency( + package, raise_on_missing=False, min_version=min_version + ) + ), + reason=msg, + ) diff --git a/kloppy/cmdline.py b/kloppy/cmdline.py index 737c462db..348be3d22 100644 --- a/kloppy/cmdline.py +++ b/kloppy/cmdline.py @@ -6,8 +6,8 @@ from kloppy import datafactory, opta, sportscode, statsbomb, wyscout from kloppy import event_pattern_matching as pm +from kloppy._utils import performance_logging from kloppy.domain import Code, CodeDataset -from kloppy.utils import performance_logging sys.path.append(".") diff --git a/kloppy/domain/models/code.py b/kloppy/domain/models/code.py index cd768237d..0e759336b 100644 --- a/kloppy/domain/models/code.py +++ b/kloppy/domain/models/code.py @@ -2,10 +2,10 @@ from datetime import timedelta from typing import Union -from kloppy.domain.models.common import DatasetType -from kloppy.utils import ( +from kloppy._utils import ( docstring_inherit_attributes, ) +from kloppy.domain.models.common import DatasetType from .common import DataRecord, Dataset diff --git a/kloppy/domain/models/common.py b/kloppy/domain/models/common.py index 3449a3559..4acd06d91 100644 --- a/kloppy/domain/models/common.py +++ b/kloppy/domain/models/common.py @@ -17,7 +17,7 @@ overload, ) -from kloppy.utils import deprecated, snake_case +from kloppy._utils import deprecated, to_snake_case if TYPE_CHECKING: from ..services.transformers.data_record import ( @@ -172,7 +172,7 @@ def full_name(self): if self.last_name: return self.last_name if self.role: - return f"{snake_case(str(self.role))}_{self.official_id}" + return f"{to_snake_case(str(self.role))}_{self.official_id}" return f"official_{self.official_id}" @@ -1930,28 +1930,12 @@ def to_df( engine = get_config("dataframe.engine") if engine == "pandas[pyarrow]": - try: - import pandas as pd + from kloppy._utils.optional import import_optional_dependency - types_mapper = pd.ArrowDtype - except ImportError: - raise ImportError( - "Seems like you don't have pandas installed. Please" - " install it using: pip install pandas" - ) - except AttributeError: - raise AttributeError( - "Seems like you have an older version of pandas installed. Please" - " upgrade to at least 1.5 using: pip install pandas>=1.5" - ) + pd = import_optional_dependency("pandas") + pa = import_optional_dependency("pyarrow") - try: - import pyarrow as pa - except ImportError: - raise ImportError( - "Seems like you don't have pyarrow installed. Please" - " install it using: pip install pyarrow" - ) + types_mapper = pd.ArrowDtype table = pa.Table.from_pydict( self.to_dict(*columns, orient="list", **named_columns) @@ -1959,27 +1943,19 @@ def to_df( return table.to_pandas(types_mapper=types_mapper) elif engine == "pandas": - try: - from pandas import DataFrame - except ImportError: - raise ImportError( - "Seems like you don't have pandas installed. Please" - " install it using: pip install pandas" - ) + from kloppy._utils.optional import import_optional_dependency + + pd = import_optional_dependency("pandas") - return DataFrame.from_dict( + return pd.DataFrame.from_dict( self.to_dict(*columns, orient="list", **named_columns) ) elif engine == "polars": - try: - from polars import from_dict - except ImportError: - raise ImportError( - "Seems like you don't have polars installed. Please" - " install it using: pip install polars" - ) + from kloppy._utils.optional import import_optional_dependency + + pl = import_optional_dependency("polars") - return from_dict( + return pl.from_dict( self.to_dict(*columns, orient="list", **named_columns) ) else: diff --git a/kloppy/domain/models/event.py b/kloppy/domain/models/event.py index 00eb9dc6c..5212b2ea0 100644 --- a/kloppy/domain/models/event.py +++ b/kloppy/domain/models/event.py @@ -14,6 +14,12 @@ ) import warnings +from kloppy._utils import ( + DeprecatedEnumValue, + docstring_inherit_attributes, + remove_suffix, + to_snake_case, +) from kloppy.domain.models.common import ( AttackingDirection, DatasetType, @@ -21,12 +27,6 @@ PositionType, ) from kloppy.domain.models.time import Time -from kloppy.utils import ( - DeprecatedEnumValue, - camelcase_to_snakecase, - docstring_inherit_attributes, - removes_suffix, -) from ...exceptions import InvalidFilterError, KloppyError, OrphanedRecordError from .common import DataRecord, Dataset, Player, Team @@ -349,9 +349,7 @@ def to_dict(self) -> dict[str, QualifierValueType]: @property def name(self): - return camelcase_to_snakecase( - removes_suffix(type(self).__name__, "Qualifier") - ) + return to_snake_case(remove_suffix(type(self).__name__, "Qualifier")) @dataclass diff --git a/kloppy/domain/models/statsbomb/event.py b/kloppy/domain/models/statsbomb/event.py index cc933cb57..75ab30b90 100644 --- a/kloppy/domain/models/statsbomb/event.py +++ b/kloppy/domain/models/statsbomb/event.py @@ -1,6 +1,6 @@ from dataclasses import dataclass -from kloppy.utils import docstring_inherit_attributes +from kloppy._utils import docstring_inherit_attributes from ... import EventFactory, create_event from ..event import PassEvent, ShotEvent diff --git a/kloppy/domain/models/tracking.py b/kloppy/domain/models/tracking.py index 695a3c1b5..fb4c31f86 100644 --- a/kloppy/domain/models/tracking.py +++ b/kloppy/domain/models/tracking.py @@ -1,10 +1,10 @@ from dataclasses import dataclass, field from typing import Any, Optional -from kloppy.domain.models.common import DatasetType -from kloppy.utils import ( +from kloppy._utils import ( docstring_inherit_attributes, ) +from kloppy.domain.models.common import DatasetType from .common import DataRecord, Dataset, Player from .pitch import Point, Point3D diff --git a/kloppy/domain/services/matchers/pattern/regexp/regexp.py b/kloppy/domain/services/matchers/pattern/regexp/regexp.py index f486c58c5..606a6becb 100644 --- a/kloppy/domain/services/matchers/pattern/regexp/regexp.py +++ b/kloppy/domain/services/matchers/pattern/regexp/regexp.py @@ -6,7 +6,7 @@ Generic, ) -import networkx as nx +from kloppy._utils.optional import import_optional_dependency # noinspection PyProtectedMember from .ast import ( @@ -22,6 +22,8 @@ ) from .matchers import Out, Tok, _TrailItem +nx = import_optional_dependency("networkx") + def ast_to_graph(root: Node) -> nx.DiGraph: """ diff --git a/kloppy/domain/services/state_builder/registered.py b/kloppy/domain/services/state_builder/registered.py index fd4800b95..75d5a7d8f 100644 --- a/kloppy/domain/services/state_builder/registered.py +++ b/kloppy/domain/services/state_builder/registered.py @@ -1,14 +1,14 @@ import abc import inspect -from kloppy.utils import camelcase_to_snakecase +from kloppy._utils import to_snake_case _STATE_BUILDER_REGISTRY: dict[str, type["StateBuilder"]] = {} # noqa: F821 class RegisteredStateBuilder(abc.ABCMeta): def __new__(mcs, cls_name, bases, class_dict): - name = camelcase_to_snakecase(cls_name) + name = to_snake_case(cls_name) class_dict["name"] = name builder_cls = super().__new__(mcs, cls_name, bases, class_dict) if not inspect.isabstract(builder_cls): diff --git a/kloppy/domain/services/transformers/attribute.py b/kloppy/domain/services/transformers/attribute.py index 798295b30..31a191bb7 100644 --- a/kloppy/domain/services/transformers/attribute.py +++ b/kloppy/domain/services/transformers/attribute.py @@ -3,6 +3,7 @@ import sys from typing import Any, Optional, Union +from kloppy._utils import to_snake_case from kloppy.domain import ( BodyPartQualifier, Code, @@ -26,7 +27,6 @@ OrientationError, UnknownEncoderError, ) -from kloppy.utils import camelcase_to_snakecase py_version = sys.version_info if py_version >= (3, 8): @@ -138,7 +138,7 @@ def create_transformer_from_qualifier( qualifier_type: type[EnumQualifier], ) -> type[EventAttributeTransformer]: enum_ = _get_generic_type_arg(qualifier_type) - name = camelcase_to_snakecase(enum_.__name__) + name = to_snake_case(enum_.__name__) options = [e.value for e in enum_] class _Transformer(EventAttributeTransformer): diff --git a/kloppy/infra/io/adapters/s3.py b/kloppy/infra/io/adapters/s3.py index 9a1ffc5e0..1bc409384 100644 --- a/kloppy/infra/io/adapters/s3.py +++ b/kloppy/infra/io/adapters/s3.py @@ -1,7 +1,6 @@ import fsspec from kloppy.config import get_config -from kloppy.exceptions import AdapterError from .fsspec import FSSpecAdapter @@ -13,13 +12,9 @@ def supports(self, url: str) -> bool: def _get_filesystem( self, url: str, no_cache: bool = False ) -> fsspec.AbstractFileSystem: - try: - import s3fs - except ImportError: - raise AdapterError( - "Seems like you don't have s3fs installed. Please" - " install it using: pip install s3fs" - ) + from kloppy._utils.optional import import_optional_dependency + + s3fs = import_optional_dependency("s3fs") s3_fs = get_config("adapters.s3.s3fs") or s3fs.S3FileSystem() diff --git a/kloppy/infra/serializers/event/datafactory/deserializer.py b/kloppy/infra/serializers/event/datafactory/deserializer.py index 2a960da6d..26556cbe1 100644 --- a/kloppy/infra/serializers/event/datafactory/deserializer.py +++ b/kloppy/infra/serializers/event/datafactory/deserializer.py @@ -4,6 +4,7 @@ import logging from typing import IO, NamedTuple +from kloppy._utils import performance_logging from kloppy.domain import ( BallState, BodyPart, @@ -29,7 +30,6 @@ ) from kloppy.exceptions import DeserializationError from kloppy.infra.serializers.event.deserializer import EventDataDeserializer -from kloppy.utils import performance_logging logger = logging.getLogger(__name__) diff --git a/kloppy/infra/serializers/event/impect/deserializer.py b/kloppy/infra/serializers/event/impect/deserializer.py index ab71b785c..500294f66 100644 --- a/kloppy/infra/serializers/event/impect/deserializer.py +++ b/kloppy/infra/serializers/event/impect/deserializer.py @@ -6,6 +6,7 @@ from typing import IO, NamedTuple, Optional, Union import warnings +from kloppy._utils import performance_logging from kloppy.domain import ( BallState, CardEvent, @@ -38,7 +39,6 @@ from kloppy.infra.serializers.event.impect.specification import ( create_impect_events, ) -from kloppy.utils import performance_logging logger = logging.getLogger(__name__) diff --git a/kloppy/infra/serializers/event/metrica/json_deserializer.py b/kloppy/infra/serializers/event/metrica/json_deserializer.py index 64a7156f8..2071aa5dd 100644 --- a/kloppy/infra/serializers/event/metrica/json_deserializer.py +++ b/kloppy/infra/serializers/event/metrica/json_deserializer.py @@ -4,6 +4,7 @@ import logging from typing import IO, NamedTuple, Optional +from kloppy._utils import performance_logging from kloppy.domain import ( BallState, BodyPart, @@ -27,7 +28,6 @@ from kloppy.infra.serializers.tracking.metrica_epts.metadata import ( load_metadata, ) -from kloppy.utils import performance_logging logger = logging.getLogger(__name__) diff --git a/kloppy/infra/serializers/event/sportec/deserializer.py b/kloppy/infra/serializers/event/sportec/deserializer.py index ca84895bd..db41a85a1 100644 --- a/kloppy/infra/serializers/event/sportec/deserializer.py +++ b/kloppy/infra/serializers/event/sportec/deserializer.py @@ -5,6 +5,7 @@ from lxml import objectify +from kloppy._utils import performance_logging from kloppy.domain import ( BallState, BodyPart, @@ -33,7 +34,6 @@ ) from kloppy.exceptions import DeserializationError from kloppy.infra.serializers.event.deserializer import EventDataDeserializer -from kloppy.utils import performance_logging position_types_mapping: dict[str, PositionType] = { "TW": PositionType.Goalkeeper, diff --git a/kloppy/infra/serializers/event/statsbomb/deserializer.py b/kloppy/infra/serializers/event/statsbomb/deserializer.py index 68cf9ae43..d60ff7c17 100644 --- a/kloppy/infra/serializers/event/statsbomb/deserializer.py +++ b/kloppy/infra/serializers/event/statsbomb/deserializer.py @@ -3,6 +3,7 @@ import logging from typing import IO, NamedTuple, Optional +from kloppy._utils import performance_logging from kloppy.domain import ( DatasetFlag, EventDataset, @@ -18,7 +19,6 @@ ) from kloppy.exceptions import DeserializationError from kloppy.infra.serializers.event.deserializer import EventDataDeserializer -from kloppy.utils import performance_logging from . import specification as SB from .helpers import parse_freeze_frame, parse_str_ts diff --git a/kloppy/infra/serializers/event/statsperform/deserializer.py b/kloppy/infra/serializers/event/statsperform/deserializer.py index 6b5e56735..fa137e018 100644 --- a/kloppy/infra/serializers/event/statsperform/deserializer.py +++ b/kloppy/infra/serializers/event/statsperform/deserializer.py @@ -5,6 +5,7 @@ import pytz +from kloppy._utils import performance_logging from kloppy.domain import ( BallState, BodyPart, @@ -41,7 +42,6 @@ ) from kloppy.exceptions import DeserializationError from kloppy.infra.serializers.event.deserializer import EventDataDeserializer -from kloppy.utils import performance_logging from .formation_mapping import formation_id_mapping, formation_position_mapping from .parsers import OptaEvent, get_parser diff --git a/kloppy/infra/serializers/event/wyscout/deserializer_v2.py b/kloppy/infra/serializers/event/wyscout/deserializer_v2.py index 2542fa589..1b611503e 100644 --- a/kloppy/infra/serializers/event/wyscout/deserializer_v2.py +++ b/kloppy/infra/serializers/event/wyscout/deserializer_v2.py @@ -4,6 +4,7 @@ import logging from typing import IO, NamedTuple, Optional +from kloppy._utils import performance_logging from kloppy.domain import ( BodyPart, BodyPartQualifier, @@ -34,7 +35,6 @@ ShotResult, Team, ) -from kloppy.utils import performance_logging from ..deserializer import EventDataDeserializer from . import wyscout_events, wyscout_tags diff --git a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py index 546747278..bff9a9d8a 100644 --- a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py +++ b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py @@ -6,6 +6,7 @@ from typing import Optional import warnings +from kloppy._utils import performance_logging from kloppy.domain import ( BodyPart, BodyPartQualifier, @@ -42,7 +43,6 @@ Team, ) from kloppy.exceptions import DeserializationError, DeserializationWarning -from kloppy.utils import performance_logging from ..deserializer import EventDataDeserializer from .deserializer_v2 import WyscoutInputs diff --git a/kloppy/infra/serializers/tracking/hawkeye/deserializer.py b/kloppy/infra/serializers/tracking/hawkeye/deserializer.py index 197d6fead..a62743e25 100644 --- a/kloppy/infra/serializers/tracking/hawkeye/deserializer.py +++ b/kloppy/infra/serializers/tracking/hawkeye/deserializer.py @@ -15,6 +15,7 @@ from dateutil.parser import parse from lxml import objectify +from kloppy._utils import performance_logging from kloppy.domain import ( AttackingDirection, Frame, @@ -33,7 +34,6 @@ ) from kloppy.exceptions import DeserializationError from kloppy.io import FileLike, get_file_extension, open_as_file -from kloppy.utils import performance_logging from ..deserializer import TrackingDataDeserializer diff --git a/kloppy/infra/serializers/tracking/metrica_csv.py b/kloppy/infra/serializers/tracking/metrica_csv.py index 909d57498..21a001434 100644 --- a/kloppy/infra/serializers/tracking/metrica_csv.py +++ b/kloppy/infra/serializers/tracking/metrica_csv.py @@ -5,6 +5,7 @@ from typing import IO, NamedTuple import warnings +from kloppy._utils import performance_logging from kloppy.domain import ( AttackingDirection, DatasetFlag, @@ -25,7 +26,6 @@ from kloppy.infra.serializers.tracking.deserializer import ( TrackingDataDeserializer, ) -from kloppy.utils import performance_logging logger = logging.getLogger(__name__) diff --git a/kloppy/infra/serializers/tracking/metrica_epts/deserializer.py b/kloppy/infra/serializers/tracking/metrica_epts/deserializer.py index 7d5cc0f83..117a2e4cc 100644 --- a/kloppy/infra/serializers/tracking/metrica_epts/deserializer.py +++ b/kloppy/infra/serializers/tracking/metrica_epts/deserializer.py @@ -2,6 +2,7 @@ import logging from typing import IO, NamedTuple +from kloppy._utils import performance_logging from kloppy.domain import ( DatasetTransformer, Frame, @@ -12,7 +13,6 @@ TrackingDataset, ) from kloppy.domain.services.frame_factory import create_frame -from kloppy.utils import performance_logging from ..deserializer import TrackingDataDeserializer from .metadata import EPTSMetadata, load_metadata diff --git a/kloppy/infra/serializers/tracking/pff.py b/kloppy/infra/serializers/tracking/pff.py index 19a6fc4a2..5ca9b769a 100644 --- a/kloppy/infra/serializers/tracking/pff.py +++ b/kloppy/infra/serializers/tracking/pff.py @@ -6,6 +6,7 @@ from dateutil.parser import parse +from kloppy._utils import performance_logging from kloppy.domain import ( AttackingDirection, BallState, @@ -29,7 +30,6 @@ from kloppy.infra.serializers.tracking.deserializer import ( TrackingDataDeserializer, ) -from kloppy.utils import performance_logging logger = logging.getLogger(__name__) diff --git a/kloppy/infra/serializers/tracking/secondspectrum.py b/kloppy/infra/serializers/tracking/secondspectrum.py index 112aa376c..e1761d7e2 100644 --- a/kloppy/infra/serializers/tracking/secondspectrum.py +++ b/kloppy/infra/serializers/tracking/secondspectrum.py @@ -6,6 +6,7 @@ from lxml import objectify +from kloppy._utils import Readable, performance_logging from kloppy.domain import ( AttackingDirection, BallState, @@ -26,7 +27,6 @@ attacking_direction_from_frame, ) from kloppy.domain.services.frame_factory import create_frame -from kloppy.utils import Readable, performance_logging from .deserializer import TrackingDataDeserializer diff --git a/kloppy/infra/serializers/tracking/signality.py b/kloppy/infra/serializers/tracking/signality.py index 4aa602975..6af30de50 100644 --- a/kloppy/infra/serializers/tracking/signality.py +++ b/kloppy/infra/serializers/tracking/signality.py @@ -5,6 +5,7 @@ from typing import IO, NamedTuple, Optional, Union import warnings +from kloppy._utils import performance_logging from kloppy.domain import ( AttackingDirection, BallState, @@ -27,7 +28,6 @@ TrackingDataDeserializer, ) from kloppy.io import FileLike, open_as_file -from kloppy.utils import performance_logging logger = logging.getLogger(__name__) diff --git a/kloppy/infra/serializers/tracking/skillcorner.py b/kloppy/infra/serializers/tracking/skillcorner.py index 9905d573e..bd3fe4c6a 100644 --- a/kloppy/infra/serializers/tracking/skillcorner.py +++ b/kloppy/infra/serializers/tracking/skillcorner.py @@ -4,6 +4,7 @@ from typing import IO, NamedTuple, Optional, Union import warnings +from kloppy._utils import performance_logging from kloppy.domain import ( AttackingDirection, BallState, @@ -28,7 +29,6 @@ from kloppy.infra.serializers.tracking.deserializer import ( TrackingDataDeserializer, ) -from kloppy.utils import performance_logging logger = logging.getLogger(__name__) diff --git a/kloppy/infra/serializers/tracking/sportec/deserializer.py b/kloppy/infra/serializers/tracking/sportec/deserializer.py index d45f347d2..d938816ed 100644 --- a/kloppy/infra/serializers/tracking/sportec/deserializer.py +++ b/kloppy/infra/serializers/tracking/sportec/deserializer.py @@ -5,6 +5,7 @@ from lxml import etree, objectify +from kloppy._utils import performance_logging from kloppy.domain import ( AttackingDirection, BallState, @@ -22,7 +23,6 @@ from kloppy.infra.serializers.event.sportec.deserializer import ( sportec_metadata_from_xml_elm, ) -from kloppy.utils import performance_logging from ..deserializer import TrackingDataDeserializer diff --git a/kloppy/infra/serializers/tracking/statsperform.py b/kloppy/infra/serializers/tracking/statsperform.py index fff8d8764..57cf67c4e 100644 --- a/kloppy/infra/serializers/tracking/statsperform.py +++ b/kloppy/infra/serializers/tracking/statsperform.py @@ -3,6 +3,7 @@ from typing import IO, NamedTuple, Optional, Union import warnings +from kloppy._utils import performance_logging from kloppy.domain import ( AttackingDirection, BallState, @@ -21,7 +22,6 @@ from kloppy.domain.services.frame_factory import create_frame from kloppy.exceptions import DeserializationError from kloppy.infra.serializers.event.statsperform.parsers import get_parser -from kloppy.utils import performance_logging from .deserializer import TrackingDataDeserializer diff --git a/kloppy/infra/serializers/tracking/tracab/deserializer.py b/kloppy/infra/serializers/tracking/tracab/deserializer.py index fb8e3067f..427e7523a 100644 --- a/kloppy/infra/serializers/tracking/tracab/deserializer.py +++ b/kloppy/infra/serializers/tracking/tracab/deserializer.py @@ -2,6 +2,7 @@ from typing import IO, NamedTuple, Optional, Union import warnings +from kloppy._utils import performance_logging from kloppy.domain import ( AttackingDirection, DatasetFlag, @@ -11,7 +12,6 @@ TrackingDataset, attacking_direction_from_frame, ) -from kloppy.utils import performance_logging from ..deserializer import TrackingDataDeserializer from .parsers import get_metadata_parser, get_raw_data_parser diff --git a/kloppy/tests/issues/issue_113/test_issue_113.py b/kloppy/tests/issues/issue_113/test_issue_113.py index 0bdf5e6a6..5e40eb20b 100644 --- a/kloppy/tests/issues/issue_113/test_issue_113.py +++ b/kloppy/tests/issues/issue_113/test_issue_113.py @@ -1,6 +1,7 @@ from pathlib import Path from kloppy import opta +from kloppy._utils.testing import skip_if_no from kloppy.domain import Orientation @@ -37,6 +38,7 @@ def kloppy_load_data(f7, f24): class TestIssue113: + @skip_if_no("pandas") def test_parse_opta(self): dir_path = Path(__file__).parent kloppy_load_data( diff --git a/kloppy/tests/issues/issue_60/test_issue_60.py b/kloppy/tests/issues/issue_60/test_issue_60.py index 78b55cbd0..ab602147b 100644 --- a/kloppy/tests/issues/issue_60/test_issue_60.py +++ b/kloppy/tests/issues/issue_60/test_issue_60.py @@ -1,9 +1,11 @@ import os from kloppy import opta +from kloppy._utils.testing import skip_if_no class TestIssue60: + @skip_if_no("pandas") def test_deleted_event_opta(self): dir_path = os.path.dirname(__file__) deleted_event_id = "2087733359" diff --git a/kloppy/tests/test_event.py b/kloppy/tests/test_event.py index 2a492ea7a..93764d2de 100644 --- a/kloppy/tests/test_event.py +++ b/kloppy/tests/test_event.py @@ -1,6 +1,7 @@ import pytest from kloppy import statsbomb +from kloppy._utils.testing import skip_if_no from kloppy.domain import EventDataset, FilteredDataset @@ -47,6 +48,7 @@ def test_navigation(self, dataset: EventDataset): assert first_goal.next(".goal").next(".goal") == goals[2] assert first_goal.next(".goal").next(".goal").next(".goal") is None + @skip_if_no("pandas") def test_filter(self, dataset: EventDataset): """ Test filtering allows simple 'css selector' (.) diff --git a/kloppy/tests/test_helpers.py b/kloppy/tests/test_helpers.py index f761ae26a..06c7c0de6 100644 --- a/kloppy/tests/test_helpers.py +++ b/kloppy/tests/test_helpers.py @@ -1,10 +1,9 @@ import sys -from pandas import DataFrame -from pandas.testing import assert_frame_equal import pytest from kloppy import opta, statsbomb, tracab +from kloppy._utils.testing import skip_if_no from kloppy.config import config_context from kloppy.domain import ( AttackingDirection, @@ -411,7 +410,11 @@ def test_transform_event_data_freeze_frame(self, base_dir): assert coordinates.x == 1 - coordinates_transformed.x assert coordinates.y == 1 - coordinates_transformed.y + @skip_if_no("pandas") def test_to_pandas(self): + from pandas import DataFrame + from pandas.testing import assert_frame_equal + tracking_data = self._get_tracking_dataset() data_frame = tracking_data.to_df(engine="pandas") @@ -437,6 +440,7 @@ def test_to_pandas(self): ) assert_frame_equal(data_frame, expected_data_frame, check_like=True) + @skip_if_no("pandas") def test_to_pandas_generic_events(self, base_dir): dataset = opta.load( f7_data=base_dir / "files/opta_f7.xml", @@ -447,6 +451,7 @@ def test_to_pandas_generic_events(self, base_dir): dataframe = dataframe[dataframe.event_type == "BALL_OUT"] assert dataframe.shape[0] == 2 + @skip_if_no("pandas") def test_to_pandas_incomplete_pass(self, base_dir): dataset = statsbomb.load( lineup_data=base_dir / "files/statsbomb_lineup.json", @@ -463,7 +468,11 @@ def test_to_pandas_incomplete_pass(self, base_dir): 0.70945, 1e-4 ) + @skip_if_no("pandas") def test_to_pandas_additional_columns(self): + from pandas import DataFrame + from pandas.testing import assert_frame_equal + tracking_data = self._get_tracking_dataset() data_frame = tracking_data.to_df( @@ -497,6 +506,7 @@ def test_to_pandas_additional_columns(self): assert_frame_equal(data_frame, expected_data_frame, check_like=True) + @skip_if_no("polars") def test_event_dataset_to_polars(self, base_dir): """ Make sure an event dataset can be exported as a Polars DataFrame @@ -512,6 +522,7 @@ def test_event_dataset_to_polars(self, base_dir): c = df.select(pl.col("event_id").count())[0, 0] assert c == 4061 + @skip_if_no("polars") def test_tracking_dataset_to_polars(self): """ Make sure a tracking dataset can be exported as a Polars DataFrame @@ -525,6 +536,8 @@ def test_tracking_dataset_to_polars(self): c = df.select(pl.col("frame_id").count())[0, 0] assert c == 2 + @skip_if_no("pandas") + @skip_if_no("polars") def test_to_df_config(self): """ Make sure to_df get engine from config. By default, pandas, otherwise polars @@ -541,6 +554,8 @@ def test_to_df_config(self): df = dataset.to_df() assert isinstance(df, pl.DataFrame) + @skip_if_no("pandas") + @skip_if_no("pyarrow") @pytest.mark.skipif(sys.version_info < (3, 8), reason="requires python3.8") def test_to_df_pyarrow(self): """ diff --git a/kloppy/tests/test_io.py b/kloppy/tests/test_io.py index 79abaddf1..d6884b2de 100644 --- a/kloppy/tests/test_io.py +++ b/kloppy/tests/test_io.py @@ -14,6 +14,7 @@ from moto.moto_server.threaded_moto_server import ThreadedMotoServer import pytest +from kloppy._utils.testing import skip_if_no from kloppy.config import config_context from kloppy.exceptions import InputNotFoundError, KloppyError from kloppy.infra.io import adapters @@ -557,6 +558,7 @@ def test_write_via_adapter(self): @pytest.mark.skipif( sys.version_info < (3, 9), reason="Patch requires Python 3.9 or higher" ) +@skip_if_no("s3fs") class TestS3Adapter: """Tests for S3Adapter using moto.""" diff --git a/kloppy/tests/test_metrica_epts.py b/kloppy/tests/test_metrica_epts.py index e9f9a2f7a..cacfe81c1 100644 --- a/kloppy/tests/test_metrica_epts.py +++ b/kloppy/tests/test_metrica_epts.py @@ -2,10 +2,11 @@ import re from lxml import objectify -from pandas import DataFrame import pytest from kloppy import metrica +from kloppy._utils import performance_logging +from kloppy._utils.testing import skip_if_no from kloppy.domain import Orientation, Point, Provider, Score from kloppy.infra.serializers.tracking.metrica_epts.metadata import ( _load_provider, @@ -15,7 +16,6 @@ build_regex, read_raw_data, ) -from kloppy.utils import performance_logging class TestMetricaEPTSTracking: @@ -63,7 +63,10 @@ def test_read(self, base_dir): with performance_logging("load"): assert list(iterator) + @skip_if_no("pandas") def test_read_to_pandas(self, base_dir): + from pandas import DataFrame + with ( open( base_dir / "files/epts_metrica_metadata.xml", "rb" @@ -78,7 +81,10 @@ def test_read_to_pandas(self, base_dir): assert "player_Track_1_x" in data_frame.columns + @skip_if_no("pandas") def test_skip_sensors(self, base_dir): + from pandas import DataFrame + with ( open( base_dir / "files/epts_metrica_metadata.xml", "rb" diff --git a/kloppy/tests/test_skillcorner.py b/kloppy/tests/test_skillcorner.py index 45cb08c0e..34a162c54 100644 --- a/kloppy/tests/test_skillcorner.py +++ b/kloppy/tests/test_skillcorner.py @@ -4,6 +4,7 @@ import pytest from kloppy import skillcorner +from kloppy._utils.testing import skip_if_no from kloppy.domain import ( BallState, DatasetType, @@ -203,6 +204,7 @@ def test_skip_dead_frames(self, meta_data: str, raw_data: str): assert len(dataset.records) == 40069 assert all([True for x in dataset if x.ball_state == BallState.ALIVE]) + @skip_if_no("pandas") def test_correct_deserialization_v3( self, raw_data_v3: Path, meta_data_v3: Path ): diff --git a/kloppy/tests/test_state_builder.py b/kloppy/tests/test_state_builder.py index 7be865bde..99e234c51 100644 --- a/kloppy/tests/test_state_builder.py +++ b/kloppy/tests/test_state_builder.py @@ -2,9 +2,9 @@ from itertools import groupby from kloppy import statsbomb, statsperform +from kloppy._utils import performance_logging from kloppy.domain import Event, EventDataset, EventType, FormationType from kloppy.domain.services.state_builder.builder import StateBuilder -from kloppy.utils import performance_logging class TestStateBuilder: diff --git a/kloppy/tests/test_xml.py b/kloppy/tests/test_xml.py index f02806545..6801dbd6f 100644 --- a/kloppy/tests/test_xml.py +++ b/kloppy/tests/test_xml.py @@ -2,10 +2,8 @@ from datetime import timedelta from io import BytesIO -from pandas import DataFrame -from pandas._testing import assert_frame_equal - from kloppy import sportscode +from kloppy._utils.testing import skip_if_no from kloppy.domain import Period from kloppy.infra.serializers.code.sportscode import ( SportsCodeOutputs, @@ -14,7 +12,11 @@ class TestXMLCodeTracking: + @skip_if_no("pandas") def test_correct_deserialization(self, base_dir): + from pandas import DataFrame + from pandas.testing import assert_frame_equal + dataset = sportscode.load(base_dir / "files/code_xml.xml") assert len(dataset.metadata.periods) == 1 diff --git a/kloppy/utils.py b/kloppy/utils.py deleted file mode 100644 index 0a2de06b2..000000000 --- a/kloppy/utils.py +++ /dev/null @@ -1,227 +0,0 @@ -from contextlib import contextmanager -import functools -import inspect -from io import BytesIO -from logging import Logger -import re -import time -from typing import BinaryIO, Optional, Union -from urllib.parse import quote -from urllib.request import Request, urlopen -import warnings - -Readable = Union[bytes, BinaryIO] - - -def to_file_object(s: Readable) -> BinaryIO: - if isinstance(s, bytes): - return BytesIO(s) - return s - - -@contextmanager -def performance_logging( - description: str, - counter: Optional[int] = None, - logger: Optional[Logger] = None, -): - start = time.time() - try: - yield - finally: - took = (time.time() - start) * 1000 - extra = "" - if counter is not None: - extra = f" ({counter / took * 1000:.1f}items/sec)" - - unit = "ms" - if took < 0.1: - took *= 1000 - unit = "us" - - msg = f"{description} took: {took:.2f}{unit} {extra}" - if logger: - logger.info(msg) - else: - print(msg) - - -_first_cap_re = re.compile("(.)([A-Z][a-z0-9]+)") -_all_cap_re = re.compile("([a-z0-9])([A-Z])") - - -def camelcase_to_snakecase(name: str) -> str: - """Convert camel-case string to snake-case.""" - s1 = _first_cap_re.sub(r"\1_\2", name) - return _all_cap_re.sub(r"\1_\2", s1).lower() - - -def removes_suffix(string: str, suffix: str) -> str: - if string[-len(suffix) :] == suffix: - return string[: -len(suffix)] - else: - return string - - -def docstring_inherit_attributes(parent): - def inherit(obj): - other_docs, attribute_docs = obj.__doc__.split("Attributes:\n") - - own_attributes = [ - attribute.strip() - for attribute in attribute_docs.strip().split("\n") - ] - - parent_attributes = [ - attribute.strip() - for attribute in parent.__doc__.split("Attributes:\n")[-1] - .strip() - .split("\n") - ] - obj.__doc__ = ( - other_docs - + "Attributes:\n " - + "\n ".join(parent_attributes) - + "\n " - + "\n ".join(own_attributes) - + "\n" - ) - return obj - - return inherit - - -string_types = (bytes, str) - - -def deprecated(reason): - """ - This is a decorator which can be used to mark functions - as deprecated. It will result in a warning being emitted - when the function is used. - """ - - if isinstance(reason, string_types): - # The @deprecated is used with a 'reason'. - # - # .. code-block:: python - # - # @deprecated("please, use another function") - # def old_function(x, y): - # pass - - def decorator(func1): - if inspect.isclass(func1): - fmt1 = "Call to deprecated class {name} ({reason})." - else: - fmt1 = "Call to deprecated function {name} ({reason})." - - @functools.wraps(func1) - def new_func1(*args, **kwargs): - warnings.simplefilter("always", DeprecationWarning) - warnings.warn( - fmt1.format(name=func1.__name__, reason=reason), - category=DeprecationWarning, - stacklevel=2, - ) - warnings.simplefilter("default", DeprecationWarning) - return func1(*args, **kwargs) - - return new_func1 - - return decorator - - elif inspect.isclass(reason) or inspect.isfunction(reason): - # The @deprecated is used without any 'reason'. - # - # .. code-block:: python - # - # @deprecated - # def old_function(x, y): - # pass - - func2 = reason - - if inspect.isclass(func2): - fmt2 = "Call to deprecated class {name}." - else: - fmt2 = "Call to deprecated function {name}." - - @functools.wraps(func2) - def new_func2(*args, **kwargs): - warnings.simplefilter("always", DeprecationWarning) - warnings.warn( - fmt2.format(name=func2.__name__), - category=DeprecationWarning, - stacklevel=2, - ) - warnings.simplefilter("default", DeprecationWarning) - return func2(*args, **kwargs) - - return new_func2 - - else: - raise TypeError(repr(type(reason))) - - -class DeprecatedEnumValue: - def __init__(self, value): - self.value = value - - def __get__(self, instance, owner): - warnings.warn( - f"{owner.__name__} is deprecated. Use GoalkeeperActionType instead.", - DeprecationWarning, - stacklevel=2, - ) - return self.value - - -def snake_case(s: str) -> str: - """Convert a string to snake_case.""" - return re.sub(r"[\s\-]+", "_", s.strip()).lower() - - -def github_resolve_raw_data_url(repository: str, branch: str, file: str) -> str: - """ - Resolve a GitHub repository file to its actual raw data URL. - - GitHub serves files differently depending on their size: - - Small files are redirected to raw.githubusercontent.com - - Large files (Git LFS) are redirected to media.githubusercontent.com - - This function follows the redirect and returns the final URL. - - Args: - repository: The repository in the format "owner/repo" (e.g., "metrica-sports/sample-data") - branch: The branch name (e.g., "master", "main") - file: The file path within the repository (e.g., "data/file.csv") - - Returns: - The resolved raw data URL - - Examples: - >>> github_resolve_raw_data_url( - ... repository="metrica-sports/sample-data", - ... branch="master", - ... file="data/Sample_Game_1/Sample_Game_1_RawTrackingData_Home_Team.csv" - ... ) - 'https://raw.githubusercontent.com/metrica-sports/sample-data/master/data/Sample_Game_1/Sample_Game_1_RawTrackingData_Home_Team.csv' - """ - # Encode the file path properly to handle spaces and special characters - encoded_file = "/".join(quote(part, safe="") for part in file.split("/")) - - # Construct the GitHub raw URL - # This URL will redirect to either raw.githubusercontent.com or media.githubusercontent.com - github_url = f"https://github.com/{repository}/raw/refs/heads/{branch}/{encoded_file}" - - # Make a HEAD request to follow redirects and get the final URL - req = Request(github_url, method="HEAD") - try: - with urlopen(req) as response: - # The final URL after following redirects - return response.url - except Exception: - # If there's an error, fall back to the standard raw.githubusercontent.com URL - # This ensures backwards compatibility - return f"https://raw.githubusercontent.com/{repository}/{branch}/{encoded_file}" diff --git a/pyproject.toml b/pyproject.toml index a0ed281b0..0db733068 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,13 @@ s3 = [ "fsspec[s3]<2026.1.0" ] pandas = [ "pandas>=2.0.3" ] polars = [ "polars>=0.16.6" ] pyarrow = [ "pyarrow>=17.0.0" ] +all = [ + "networkx>=2.4,<3", + "fsspec[s3]", + "pandas>=2.0.3", + "polars>=0.16.6", + "pyarrow>=17.0.0", +] # ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Scripts ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # diff --git a/uv.lock b/uv.lock index 1e841f2fc..6f0902ed5 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 2 requires-python = ">=3.9" resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", @@ -78,14 +78,14 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "aiohappyeyeballs", version = "2.6.1", source = { registry = "https://pypi.org/simple" } }, - { name = "aiosignal" }, - { name = "async-timeout" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache", version = "0.4.1", source = { registry = "https://pypi.org/simple" } }, - { name = "yarl", version = "1.22.0", source = { registry = "https://pypi.org/simple" } }, + { name = "aiohappyeyeballs", version = "2.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "aiosignal", marker = "python_full_version < '3.10'" }, + { name = "async-timeout", marker = "python_full_version < '3.10'" }, + { name = "attrs", marker = "python_full_version < '3.10'" }, + { name = "frozenlist", marker = "python_full_version < '3.10'" }, + { name = "multidict", marker = "python_full_version < '3.10'" }, + { name = "propcache", version = "0.4.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "yarl", version = "1.22.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/77/9a/152096d4808df8e4268befa55fba462f440f14beab85e8ad9bf990516918/aiohttp-3.13.5.tar.gz", hash = "sha256:9d98cc980ecc96be6eb4c1994ce35d28d8b1f5e5208a23b421187d1209dbb7d1", size = 7858271, upload-time = "2026-03-31T22:01:03.343Z" } wheels = [ @@ -227,15 +227,15 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "aiohappyeyeballs", version = "2.7.1", source = { registry = "https://pypi.org/simple" } }, - { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache", version = "0.5.2", source = { registry = "https://pypi.org/simple" } }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, - { name = "yarl", version = "1.24.5", source = { registry = "https://pypi.org/simple" } }, + { name = "aiohappyeyeballs", version = "2.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "aiosignal", marker = "python_full_version >= '3.10'" }, + { name = "async-timeout", marker = "python_full_version == '3.10.*'" }, + { name = "attrs", marker = "python_full_version >= '3.10'" }, + { name = "frozenlist", marker = "python_full_version >= '3.10'" }, + { name = "multidict", marker = "python_full_version >= '3.10'" }, + { name = "propcache", version = "0.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" }, + { name = "yarl", version = "1.24.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/58/d9/22ce5786ac0c1653ae8b6c23bded02c1686d11f0dbb45b31ce128e0df985/aiohttp-3.14.3.tar.gz", hash = "sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc", size = 7971213, upload-time = "2026-07-23T01:57:27.037Z" } wheels = [ @@ -470,10 +470,10 @@ resolution-markers = [ "python_full_version > '3.9' and python_full_version < '3.10'", ] dependencies = [ - { name = "boto3" }, - { name = "jsonschema", version = "4.25.1", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic", version = "2.12.4", source = { registry = "https://pypi.org/simple" } }, - { name = "typing-extensions" }, + { name = "boto3", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "jsonschema", version = "4.25.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "pydantic", version = "2.12.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "typing-extensions", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d0/e3/82cc7240504b1c0d2d7ed7028b05ccceedb02932b8638c61a8372a5d875f/aws_sam_translator-1.103.0.tar.gz", hash = "sha256:8317b72ef412db581dc7846932a44dfc1729adea578d9307a3e6ece46a7882ca", size = 344881, upload-time = "2025-11-21T19:50:51.818Z" } wheels = [ @@ -497,10 +497,10 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "boto3" }, - { name = "jsonschema", version = "4.26.0", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic", version = "2.13.4", source = { registry = "https://pypi.org/simple" } }, - { name = "typing-extensions" }, + { name = "boto3", marker = "python_full_version >= '3.10'" }, + { name = "jsonschema", version = "4.26.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pydantic", version = "2.13.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8e/31/4e6d6f0b9d4ead8eaa1c13a14d86834e7691acf5726fb49de98f8e195028/aws_sam_translator-1.111.0.tar.gz", hash = "sha256:6884d94e28dc20384e5e0396e9386a456fe59303d706924deb2646329b4d97d3", size = 374368, upload-time = "2026-07-02T00:31:39.601Z" } wheels = [ @@ -512,8 +512,8 @@ name = "aws-xray-sdk" version = "2.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "botocore" }, - { name = "wrapt" }, + { name = "botocore", marker = "python_full_version > '3.9'" }, + { name = "wrapt", marker = "python_full_version > '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/14/25/0cbd7a440080def5e6f063720c3b190a25f8aa2938c1e34415dc18241596/aws_xray_sdk-2.15.0.tar.gz", hash = "sha256:794381b96e835314345068ae1dd3b9120bd8b4e21295066c37e8814dbb341365", size = 76315, upload-time = "2025-10-29T20:59:45Z" } wheels = [ @@ -595,7 +595,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "webencodings" }, + { name = "webencodings", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/76/9a/0e33f5054c54d349ea62c277191c020c2d6ef1d65ab2cb1993f91ec846d1/bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f", size = 203083, upload-time = "2024-10-29T18:30:40.477Z" } wheels = [ @@ -604,7 +604,7 @@ wheels = [ [package.optional-dependencies] css = [ - { name = "tinycss2", version = "1.4.0", source = { registry = "https://pypi.org/simple" } }, + { name = "tinycss2", version = "1.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] [[package]] @@ -624,7 +624,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "webencodings" }, + { name = "webencodings", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/48/3c/e12ac860709702bd5ebeb9b56a4fe334f1001246ee1b8f2b7ee28912df7d/bleach-6.4.0.tar.gz", hash = "sha256:4202482733d85cedd04e59fcb2f89f4e4c7c385a78d3c3c23c30446843a37452", size = 204857, upload-time = "2026-06-05T13:01:13.734Z" } wheels = [ @@ -633,7 +633,7 @@ wheels = [ [package.optional-dependencies] css = [ - { name = "tinycss2", version = "1.5.1", source = { registry = "https://pypi.org/simple" } }, + { name = "tinycss2", version = "1.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] [[package]] @@ -701,7 +701,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "pycparser", version = "2.23", source = { registry = "https://pypi.org/simple" }, marker = "implementation_name != 'PyPy'" }, + { name = "pycparser", version = "2.23", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' and implementation_name != 'PyPy'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ @@ -807,7 +807,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "pycparser", version = "3.0", source = { registry = "https://pypi.org/simple" }, marker = "implementation_name != 'PyPy'" }, + { name = "pycparser", version = "3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' and implementation_name != 'PyPy'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/57/5f/ff100cae70ebe9d8df1c01a00e510e45d9adb5c1fdda84791b199141de97/cffi-2.1.0.tar.gz", hash = "sha256:efc1cdd798b1aaf39b4610bba7aad28c9bea9b910f25c784ccf9ec1fa719d1f9", size = 531036, upload-time = "2026-07-06T21:34:30.382Z" } wheels = [ @@ -954,13 +954,13 @@ resolution-markers = [ "python_full_version > '3.9' and python_full_version < '3.10'", ] dependencies = [ - { name = "aws-sam-translator", version = "1.103.0", source = { registry = "https://pypi.org/simple" } }, - { name = "jsonpatch" }, - { name = "networkx" }, - { name = "pyyaml" }, - { name = "regex", version = "2026.1.15", source = { registry = "https://pypi.org/simple" } }, - { name = "sympy" }, - { name = "typing-extensions" }, + { name = "aws-sam-translator", version = "1.103.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "jsonpatch", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "networkx", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "pyyaml", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "regex", version = "2026.1.15", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "sympy", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "typing-extensions", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ee/b5/436c192cdf8dbddd8e09a591384f126c5a47937c14953d87b1dacacd0543/cfn_lint-1.41.0.tar.gz", hash = "sha256:6feca1cf57f9ed2833bab68d9b1d38c8033611e571fa792e45ab4a39e2b8ab57", size = 3408534, upload-time = "2025-11-18T20:03:33.431Z" } wheels = [ @@ -984,13 +984,13 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "aws-sam-translator", version = "1.111.0", source = { registry = "https://pypi.org/simple" } }, - { name = "jsonpatch" }, - { name = "networkx" }, - { name = "pyyaml" }, - { name = "regex", version = "2026.7.19", source = { registry = "https://pypi.org/simple" } }, - { name = "sympy" }, - { name = "typing-extensions" }, + { name = "aws-sam-translator", version = "1.111.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "jsonpatch", marker = "python_full_version >= '3.10'" }, + { name = "networkx", marker = "python_full_version >= '3.10'" }, + { name = "pyyaml", marker = "python_full_version >= '3.10'" }, + { name = "regex", version = "2026.7.19", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "sympy", marker = "python_full_version >= '3.10'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c2/82/f8f1b7437077a1b203141e3c9d2b9550748062ea761496a86610a1e0c3c9/cfn_lint-1.53.2.tar.gz", hash = "sha256:f2f4a63bc0e6dce802cc429993e6c7b2a4dac4bc1f4b0e743709cb684fad345b", size = 4593047, upload-time = "2026-07-23T19:29:56.634Z" } wheels = [ @@ -1106,7 +1106,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } wheels = [ @@ -1130,7 +1130,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" } wheels = [ @@ -1164,7 +1164,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" } }, + { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f5/f6/31a8f28b4a2a4fa0e01085e542f3081ab0588eff8e589d39d775172c9792/contourpy-1.3.0.tar.gz", hash = "sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4", size = 13464370, upload-time = "2024-08-27T21:00:03.328Z" } wheels = [ @@ -1242,7 +1242,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } wheels = [ @@ -1320,7 +1320,7 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } @@ -1412,9 +1412,9 @@ name = "cryptography" version = "50.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cffi", version = "2.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10' and platform_python_implementation != 'PyPy'" }, + { name = "cffi", version = "2.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10' and platform_python_implementation != 'PyPy'" }, { name = "cffi", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10' and platform_python_implementation != 'PyPy'" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version > '3.9' and python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/de/41/6cbdcf9142d00fe82836fbb51e503e58088575cf7a0fe1dbff6695bf0840/cryptography-50.0.0.tar.gz", hash = "sha256:eeac2acb5a20ed25e0ad6d1df9891a520b78b404266b6d11778f25d5d691a6c9", size = 880201, upload-time = "2026-07-31T14:25:10.11Z" } wheels = [ @@ -1548,10 +1548,10 @@ name = "docker" version = "7.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "pywin32", marker = "python_full_version > '3.9' and sys_platform == 'win32'" }, + { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, { name = "requests", version = "2.34.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, { name = "urllib3", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/88/7f/731ff914b0255d3d065f45fd4e626d4b8c95dbcbaada049f337a6ac16410/docker-7.2.0.tar.gz", hash = "sha256:cebb93773d334f778e023a7ee352a8d6e13ab1bd3b863a4d4a59dec897df43ac", size = 118731, upload-time = "2026-07-09T14:53:46.39Z" } @@ -1564,7 +1564,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1672,9 +1672,9 @@ name = "flask-cors" version = "6.0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "flask" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, - { name = "werkzeug" }, + { name = "flask", marker = "python_full_version > '3.9'" }, + { name = "typing-extensions", marker = "python_full_version > '3.9' and python_full_version < '3.11'" }, + { name = "werkzeug", marker = "python_full_version > '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/47/03/4e464a50860f9adf08b5c1d3479cb8ea1f12af2aa69535c7042c6e628135/flask_cors-6.0.5.tar.gz", hash = "sha256:30c5031552cd59f620ac0c8211dac45b345d3b2df310e7721879e4f46ef9c601", size = 101386, upload-time = "2026-06-08T20:20:17.765Z" } wheels = [ @@ -1971,10 +1971,10 @@ wheels = [ [package.optional-dependencies] http = [ - { name = "aiohttp", version = "3.13.5", source = { registry = "https://pypi.org/simple" } }, + { name = "aiohttp", version = "3.13.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] s3 = [ - { name = "s3fs", version = "2025.10.0", source = { registry = "https://pypi.org/simple" } }, + { name = "s3fs", version = "2025.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] [[package]] @@ -2000,10 +2000,10 @@ wheels = [ [package.optional-dependencies] http = [ - { name = "aiohttp", version = "3.14.3", source = { registry = "https://pypi.org/simple" } }, + { name = "aiohttp", version = "3.14.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] s3 = [ - { name = "s3fs", version = "2025.12.0", source = { registry = "https://pypi.org/simple" } }, + { name = "s3fs", version = "2025.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] [[package]] @@ -2023,7 +2023,7 @@ name = "graphql-core" version = "3.2.11" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.10'" }, + { name = "typing-extensions", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4d/90/f2aff026ab4aebd80eb71905106a0885f4cfde85dcf965543f45bed0d9ee/graphql_core-3.2.11.tar.gz", hash = "sha256:e7e156d10beb127cab5c89ff0da71416fc73d27c484a4757d3b2d35633774802", size = 528407, upload-time = "2026-06-05T13:45:22.915Z" } wheels = [ @@ -2039,7 +2039,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "colorama" }, + { name = "colorama", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ec/d7/6c09dd7ce4c7837e4cdb11dce980cb45ae3cd87677298dc3b781b6bce7d3/griffe-1.14.0.tar.gz", hash = "sha256:9d2a15c1eca966d68e00517de5d69dd1bc5c9f2335ef6c1775362ba5b8651a13", size = 424684, upload-time = "2025-09-05T15:02:29.167Z" } wheels = [ @@ -2063,7 +2063,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "colorama" }, + { name = "colorama", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0d/0c/3a471b6e31951dce2360477420d0a8d1e00dea6cf33b70f3e8c3ab6e28e1/griffe-1.15.0.tar.gz", hash = "sha256:7726e3afd6f298fbc3696e67958803e7ac843c1cfe59734b6251a40cdbfb5eea", size = 424112, upload-time = "2025-11-10T15:03:15.52Z" } wheels = [ @@ -2141,7 +2141,7 @@ name = "importlib-metadata" version = "8.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "zipp" }, + { name = "zipp", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" } wheels = [ @@ -2153,7 +2153,7 @@ name = "importlib-resources" version = "6.5.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "zipp" }, + { name = "zipp", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cf/8c/f834fbf984f691b4f7ff60f50b514cc3de5cc08abfc3295564dd89c5e2e7/importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c", size = 44693, upload-time = "2025-01-03T18:51:56.698Z" } wheels = [ @@ -2203,19 +2203,19 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "appnope", marker = "sys_platform == 'darwin'" }, - { name = "comm" }, - { name = "debugpy" }, - { name = "ipython", version = "8.18.1", source = { registry = "https://pypi.org/simple" } }, - { name = "jupyter-client", version = "8.6.3", source = { registry = "https://pypi.org/simple" } }, - { name = "jupyter-core", version = "5.8.1", source = { registry = "https://pypi.org/simple" } }, - { name = "matplotlib-inline" }, - { name = "nest-asyncio" }, - { name = "packaging" }, - { name = "psutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, + { name = "appnope", marker = "python_full_version < '3.10' and sys_platform == 'darwin'" }, + { name = "comm", marker = "python_full_version < '3.10'" }, + { name = "debugpy", marker = "python_full_version < '3.10'" }, + { name = "ipython", version = "8.18.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "jupyter-client", version = "8.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "jupyter-core", version = "5.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "matplotlib-inline", marker = "python_full_version < '3.10'" }, + { name = "nest-asyncio", marker = "python_full_version < '3.10'" }, + { name = "packaging", marker = "python_full_version < '3.10'" }, + { name = "psutil", marker = "python_full_version < '3.10'" }, + { name = "pyzmq", marker = "python_full_version < '3.10'" }, + { name = "tornado", marker = "python_full_version < '3.10'" }, + { name = "traitlets", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a5/1d/d5ba6edbfe6fae4c3105bca3a9c889563cc752c7f2de45e333164c7f4846/ipykernel-6.31.0.tar.gz", hash = "sha256:2372ce8bc1ff4f34e58cafed3a0feb2194b91fc7cad0fc72e79e47b45ee9e8f6", size = 167493, upload-time = "2025-10-20T11:42:39.948Z" } wheels = [ @@ -2239,20 +2239,20 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "appnope", marker = "sys_platform == 'darwin'" }, - { name = "comm" }, - { name = "debugpy" }, - { name = "ipython", version = "8.39.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "appnope", marker = "python_full_version >= '3.10' and sys_platform == 'darwin'" }, + { name = "comm", marker = "python_full_version >= '3.10'" }, + { name = "debugpy", marker = "python_full_version >= '3.10'" }, + { name = "ipython", version = "8.39.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, { name = "ipython", version = "9.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "jupyter-client", version = "8.9.1", source = { registry = "https://pypi.org/simple" } }, - { name = "jupyter-core", version = "5.9.1", source = { registry = "https://pypi.org/simple" } }, - { name = "matplotlib-inline" }, - { name = "nest-asyncio2" }, - { name = "packaging" }, - { name = "psutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, + { name = "jupyter-client", version = "8.9.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "jupyter-core", version = "5.9.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "matplotlib-inline", marker = "python_full_version >= '3.10'" }, + { name = "nest-asyncio2", marker = "python_full_version >= '3.10'" }, + { name = "packaging", marker = "python_full_version >= '3.10'" }, + { name = "psutil", marker = "python_full_version >= '3.10'" }, + { name = "pyzmq", marker = "python_full_version >= '3.10'" }, + { name = "tornado", marker = "python_full_version >= '3.10'" }, + { name = "traitlets", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3d/c4/e4a38f579de4225a561305666f7541cdabb30075def2aa1ac17bd73c1fb5/ipykernel-7.3.0.tar.gz", hash = "sha256:9acaaaf97d16355166e4085afe9d225bfbdf2b7ef520f9df3be8f2b248275e09", size = 184899, upload-time = "2026-06-10T08:41:25.481Z" } wheels = [ @@ -2268,17 +2268,17 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "decorator" }, - { name = "exceptiongroup" }, - { name = "jedi", version = "0.19.2", source = { registry = "https://pypi.org/simple" } }, - { name = "matplotlib-inline" }, - { name = "pexpect", marker = "sys_platform != 'win32'" }, - { name = "prompt-toolkit", version = "3.0.52", source = { registry = "https://pypi.org/simple" } }, - { name = "pygments" }, - { name = "stack-data" }, - { name = "traitlets" }, - { name = "typing-extensions" }, + { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" }, + { name = "decorator", marker = "python_full_version < '3.10'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.10'" }, + { name = "jedi", version = "0.19.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "matplotlib-inline", marker = "python_full_version < '3.10'" }, + { name = "pexpect", marker = "python_full_version < '3.10' and sys_platform != 'win32'" }, + { name = "prompt-toolkit", version = "3.0.52", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "pygments", marker = "python_full_version < '3.10'" }, + { name = "stack-data", marker = "python_full_version < '3.10'" }, + { name = "traitlets", marker = "python_full_version < '3.10'" }, + { name = "typing-extensions", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b1/b9/3ba6c45a6df813c09a48bac313c22ff83efa26cbb55011218d925a46e2ad/ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27", size = 5486330, upload-time = "2023-11-27T09:58:34.596Z" } wheels = [ @@ -2293,17 +2293,17 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "decorator" }, - { name = "exceptiongroup" }, - { name = "jedi", version = "0.20.0", source = { registry = "https://pypi.org/simple" } }, - { name = "matplotlib-inline" }, - { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "prompt-toolkit", version = "3.0.53", source = { registry = "https://pypi.org/simple" } }, - { name = "pygments" }, - { name = "stack-data" }, - { name = "traitlets" }, - { name = "typing-extensions" }, + { name = "colorama", marker = "python_full_version == '3.10.*' and sys_platform == 'win32'" }, + { name = "decorator", marker = "python_full_version == '3.10.*'" }, + { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" }, + { name = "jedi", version = "0.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "matplotlib-inline", marker = "python_full_version == '3.10.*'" }, + { name = "pexpect", marker = "python_full_version == '3.10.*' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit", version = "3.0.53", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "pygments", marker = "python_full_version == '3.10.*'" }, + { name = "stack-data", marker = "python_full_version == '3.10.*'" }, + { name = "traitlets", marker = "python_full_version == '3.10.*'" }, + { name = "typing-extensions", marker = "python_full_version == '3.10.*'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/40/18/f8598d287006885e7136451fdea0755af4ebcbfe342836f24deefaed1164/ipython-8.39.0.tar.gz", hash = "sha256:4110ae96012c379b8b6db898a07e186c40a2a1ef5d57a7fa83166047d9da7624", size = 5513971, upload-time = "2026-03-27T10:02:13.94Z" } wheels = [ @@ -2326,18 +2326,18 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "decorator" }, - { name = "ipython-pygments-lexers" }, - { name = "jedi", version = "0.20.0", source = { registry = "https://pypi.org/simple" } }, - { name = "matplotlib-inline" }, - { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "prompt-toolkit", version = "3.0.53", source = { registry = "https://pypi.org/simple" } }, - { name = "psutil", marker = "sys_platform != 'cygwin' and sys_platform != 'emscripten'" }, - { name = "pygments" }, - { name = "stack-data" }, - { name = "traitlets" }, - { name = "typing-extensions", marker = "python_full_version < '3.12'" }, + { name = "colorama", marker = "python_full_version >= '3.11' and sys_platform == 'win32'" }, + { name = "decorator", marker = "python_full_version >= '3.11'" }, + { name = "ipython-pygments-lexers", marker = "python_full_version >= '3.11'" }, + { name = "jedi", version = "0.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "matplotlib-inline", marker = "python_full_version >= '3.11'" }, + { name = "pexpect", marker = "python_full_version >= '3.11' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit", version = "3.0.53", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "psutil", marker = "python_full_version >= '3.11' and sys_platform != 'cygwin' and sys_platform != 'emscripten'" }, + { name = "pygments", marker = "python_full_version >= '3.11'" }, + { name = "stack-data", marker = "python_full_version >= '3.11'" }, + { name = "traitlets", marker = "python_full_version >= '3.11'" }, + { name = "typing-extensions", marker = "python_full_version == '3.11.*'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/53/59/165d3b4d75cc34add3122c4417ecb229085140ac573103c223cd01dde96f/ipython-9.15.0.tar.gz", hash = "sha256:da2819ce2aa83135257df830660b1176d986c3d2876db24df01974fa955b2756", size = 4442580, upload-time = "2026-06-26T11:03:35.913Z" } wheels = [ @@ -2349,7 +2349,7 @@ name = "ipython-pygments-lexers" version = "1.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pygments" }, + { name = "pygments", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } wheels = [ @@ -2374,7 +2374,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "parso" }, + { name = "parso", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } wheels = [ @@ -2398,7 +2398,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "parso" }, + { name = "parso", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/46/b7/a3635f6a2d7cf5b5dd98064fc1d5fbbafcb25477bcea204a3a92145d158b/jedi-0.20.0.tar.gz", hash = "sha256:c3f4ccbd276696f4b19c54618d4fb18f9fc24b0aef02acf704b23f487daa1011", size = 3119416, upload-time = "2026-05-01T23:38:47.814Z" } wheels = [ @@ -2434,7 +2434,7 @@ resolution-markers = [ "python_full_version > '3.9' and python_full_version < '3.10'", ] dependencies = [ - { name = "cryptography" }, + { name = "cryptography", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5d/ac/d4fd5b30f82900eac60d765f179f0ba005825ac462cc8ced6e13ec685ab3/joserfc-1.6.8.tar.gz", hash = "sha256:878620c553a6ebdd76ccdc356782fee3f735f21a356d079a546b42a4670ace5f", size = 232930, upload-time = "2026-05-27T03:22:37.819Z" } wheels = [ @@ -2458,7 +2458,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "cryptography" }, + { name = "cryptography", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c7/e0/27a6a081ae25420eda6768ceae05d7022a7f2447f420588843f2a44e4298/joserfc-1.7.4.tar.gz", hash = "sha256:b3bc561672ae541b17a9237053b48a03dacddd92d68047b3ecdfb4b5714a88ed", size = 234027, upload-time = "2026-07-19T15:43:02.739Z" } wheels = [ @@ -2470,7 +2470,7 @@ name = "jsonpatch" version = "1.33" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "jsonpointer", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "jsonpointer", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, { name = "jsonpointer", version = "3.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699, upload-time = "2023-06-26T12:07:29.144Z" } @@ -2529,10 +2529,10 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "attrs" }, - { name = "jsonschema-specifications" }, - { name = "referencing", version = "0.36.2", source = { registry = "https://pypi.org/simple" } }, - { name = "rpds-py", version = "0.27.1", source = { registry = "https://pypi.org/simple" } }, + { name = "attrs", marker = "python_full_version < '3.10'" }, + { name = "jsonschema-specifications", marker = "python_full_version < '3.10'" }, + { name = "referencing", version = "0.36.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "rpds-py", version = "0.27.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } wheels = [ @@ -2556,10 +2556,10 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "attrs" }, - { name = "jsonschema-specifications" }, - { name = "referencing", version = "0.37.0", source = { registry = "https://pypi.org/simple" } }, - { name = "rpds-py", version = "0.30.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "attrs", marker = "python_full_version >= '3.10'" }, + { name = "jsonschema-specifications", marker = "python_full_version >= '3.10'" }, + { name = "referencing", version = "0.37.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "rpds-py", version = "0.30.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, { name = "rpds-py", version = "2026.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } @@ -2575,10 +2575,10 @@ resolution-markers = [ "python_full_version > '3.9' and python_full_version < '3.10'", ] dependencies = [ - { name = "pathable", version = "0.4.4", source = { registry = "https://pypi.org/simple" } }, - { name = "pyyaml" }, - { name = "referencing", version = "0.36.2", source = { registry = "https://pypi.org/simple" } }, - { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" } }, + { name = "pathable", version = "0.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "pyyaml", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "referencing", version = "0.36.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6e/45/41ebc679c2a4fced6a722f624c18d658dee42612b83ea24c1caf7c0eb3a8/jsonschema_path-0.3.4.tar.gz", hash = "sha256:8365356039f16cc65fddffafda5f58766e34bebab7d6d105616ab52bc4297001", size = 11159, upload-time = "2025-01-24T14:33:16.547Z" } wheels = [ @@ -2602,10 +2602,10 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "attrs" }, - { name = "pathable", version = "0.6.0", source = { registry = "https://pypi.org/simple" } }, - { name = "pyyaml" }, - { name = "referencing", version = "0.37.0", source = { registry = "https://pypi.org/simple" } }, + { name = "attrs", marker = "python_full_version >= '3.10'" }, + { name = "pathable", version = "0.6.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pyyaml", marker = "python_full_version >= '3.10'" }, + { name = "referencing", version = "0.37.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/39/79/cd02a4df6d9270efdc7d3feefe6edd730b0820c39eeaa107a2faee8322d5/jsonschema_path-0.5.0.tar.gz", hash = "sha256:493b156ba895c97602655b620a8456caa2ce08c1aa389f5a7addec065e6e855c", size = 19597, upload-time = "2026-05-19T20:45:00.971Z" } wheels = [ @@ -2634,12 +2634,12 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "importlib-metadata" }, - { name = "jupyter-core", version = "5.8.1", source = { registry = "https://pypi.org/simple" } }, - { name = "python-dateutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, + { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, + { name = "jupyter-core", version = "5.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "python-dateutil", marker = "python_full_version < '3.10'" }, + { name = "pyzmq", marker = "python_full_version < '3.10'" }, + { name = "tornado", marker = "python_full_version < '3.10'" }, + { name = "traitlets", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019, upload-time = "2024-09-17T10:44:17.613Z" } wheels = [ @@ -2663,12 +2663,12 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "jupyter-core", version = "5.9.1", source = { registry = "https://pypi.org/simple" } }, - { name = "python-dateutil" }, - { name = "pyzmq" }, - { name = "tornado" }, - { name = "traitlets" }, - { name = "typing-extensions" }, + { name = "jupyter-core", version = "5.9.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "python-dateutil", marker = "python_full_version >= '3.10'" }, + { name = "pyzmq", marker = "python_full_version >= '3.10'" }, + { name = "tornado", marker = "python_full_version >= '3.10'" }, + { name = "traitlets", marker = "python_full_version >= '3.10'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7d/dc/5512503b088997c2250b8bf18258fba9d9ce5ead641183700960d3c9d342/jupyter_client-8.9.1.tar.gz", hash = "sha256:a58f730dd9e728ba16ba1d62ebccf7ffe1ebbdbce4e95cfae941b7321ae1f4fa", size = 359256, upload-time = "2026-06-09T13:15:01.033Z" } wheels = [ @@ -2684,9 +2684,9 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" } }, - { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, - { name = "traitlets" }, + { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "pywin32", marker = "python_full_version < '3.10' and platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, + { name = "traitlets", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/99/1b/72906d554acfeb588332eaaa6f61577705e9ec752ddb486f302dafa292d9/jupyter_core-5.8.1.tar.gz", hash = "sha256:0a5f9706f70e64786b75acba995988915ebd4601c8a52e534a40b51c95f59941", size = 88923, upload-time = "2025-05-27T07:38:16.655Z" } wheels = [ @@ -2710,8 +2710,8 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "platformdirs", version = "4.11.0", source = { registry = "https://pypi.org/simple" } }, - { name = "traitlets" }, + { name = "platformdirs", version = "4.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "traitlets", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } wheels = [ @@ -3001,6 +3001,17 @@ dependencies = [ ] [package.optional-dependencies] +all = [ + { name = "fsspec", version = "2025.10.0", source = { registry = "https://pypi.org/simple" }, extra = ["s3"], marker = "python_full_version < '3.10'" }, + { name = "fsspec", version = "2025.12.0", source = { registry = "https://pypi.org/simple" }, extra = ["s3"], marker = "python_full_version >= '3.10'" }, + { name = "networkx" }, + { name = "pandas", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "pandas", version = "3.0.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "polars", version = "1.36.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "polars", version = "1.43.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pyarrow", version = "21.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "pyarrow", version = "25.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, +] pandas = [ { name = "pandas", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "pandas", version = "3.0.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, @@ -3061,18 +3072,23 @@ nb = [ [package.metadata] requires-dist = [ { name = "fsspec", extras = ["http"], specifier = ">=2024.12.0" }, + { name = "fsspec", extras = ["s3"], marker = "extra == 'all'" }, { name = "fsspec", extras = ["s3"], marker = "extra == 's3'", specifier = "<2026.1.0" }, { name = "lxml", specifier = ">=4.4.0" }, + { name = "networkx", marker = "extra == 'all'", specifier = ">=2.4,<3" }, { name = "networkx", marker = "extra == 'query'", specifier = ">=2.4,<3" }, + { name = "pandas", marker = "extra == 'all'", specifier = ">=2.0.3" }, { name = "pandas", marker = "extra == 'pandas'", specifier = ">=2.0.3" }, + { name = "polars", marker = "extra == 'all'", specifier = ">=0.16.6" }, { name = "polars", marker = "extra == 'polars'", specifier = ">=0.16.6" }, + { name = "pyarrow", marker = "extra == 'all'", specifier = ">=17.0.0" }, { name = "pyarrow", marker = "extra == 'pyarrow'", specifier = ">=17.0.0" }, { name = "python-dateutil", specifier = ">=2.9.0.post0" }, { name = "pytz", specifier = ">=2025.2" }, { name = "sortedcontainers", specifier = ">=2" }, { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] -provides-extras = ["query", "s3", "pandas", "polars", "pyarrow"] +provides-extras = ["query", "s3", "pandas", "polars", "pyarrow", "all"] [package.metadata.requires-dev] dev = [ @@ -3294,7 +3310,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "importlib-metadata" }, + { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8d/37/02347f6d6d8279247a5837082ebc26fc0d5aaeaf75aa013fcbb433c777ab/markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a", size = 364585, upload-time = "2025-09-04T20:25:22.885Z" } wheels = [ @@ -3331,7 +3347,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "pymdown-extensions", version = "10.21.3", source = { registry = "https://pypi.org/simple" } }, + { name = "pymdown-extensions", version = "10.21.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e8/e4/ddd5ca350f2b072e51a22359cb51e94b5fdbe85810351e7484ccfd923324/markdown_exec-1.11.0.tar.gz", hash = "sha256:e0313a0dff715869a311d24853b3a7ecbbaa12e74eb0f3cf7d91401a7d8f0082", size = 81826, upload-time = "2025-06-28T10:30:43.781Z" } wheels = [ @@ -3340,7 +3356,7 @@ wheels = [ [package.optional-dependencies] ansi = [ - { name = "pygments-ansi-color" }, + { name = "pygments-ansi-color", marker = "python_full_version < '3.10'" }, ] [[package]] @@ -3360,7 +3376,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "pymdown-extensions", version = "11.0.1", source = { registry = "https://pypi.org/simple" } }, + { name = "pymdown-extensions", version = "11.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6d/76/c47da8edb6a12b066728432fb3724109d9d91de5331df5073d12d272493f/markdown_exec-1.12.3.tar.gz", hash = "sha256:006b9cac46470a9499797bc9c579305ae4719e0a8e495e5401dfbf1e66ce7fb4", size = 77841, upload-time = "2026-07-07T09:53:13.838Z" } wheels = [ @@ -3369,7 +3385,7 @@ wheels = [ [package.optional-dependencies] ansi = [ - { name = "pygments-ansi-color" }, + { name = "pygments-ansi-color", marker = "python_full_version >= '3.10'" }, ] [[package]] @@ -3381,7 +3397,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "mdurl" }, + { name = "mdurl", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } wheels = [ @@ -3405,7 +3421,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "mdurl" }, + { name = "mdurl", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } wheels = [ @@ -3517,16 +3533,16 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "contourpy", version = "1.3.0", source = { registry = "https://pypi.org/simple" } }, - { name = "cycler" }, - { name = "fonttools", version = "4.60.2", source = { registry = "https://pypi.org/simple" } }, - { name = "importlib-resources" }, - { name = "kiwisolver", version = "1.4.7", source = { registry = "https://pypi.org/simple" } }, - { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" } }, - { name = "packaging" }, - { name = "pillow", version = "11.3.0", source = { registry = "https://pypi.org/simple" } }, - { name = "pyparsing" }, - { name = "python-dateutil" }, + { name = "contourpy", version = "1.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "cycler", marker = "python_full_version < '3.10'" }, + { name = "fonttools", version = "4.60.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "importlib-resources", marker = "python_full_version < '3.10'" }, + { name = "kiwisolver", version = "1.4.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "packaging", marker = "python_full_version < '3.10'" }, + { name = "pillow", version = "11.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "pyparsing", marker = "python_full_version < '3.10'" }, + { name = "python-dateutil", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/df/17/1747b4154034befd0ed33b52538f5eb7752d05bb51c5e2a31470c3bc7d52/matplotlib-3.9.4.tar.gz", hash = "sha256:1e00e8be7393cbdc6fedfa8a6fba02cf3e83814b285db1c60b906a023ba41bc3", size = 36106529, upload-time = "2024-12-13T05:56:34.184Z" } wheels = [ @@ -3580,15 +3596,15 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "contourpy", version = "1.3.2", source = { registry = "https://pypi.org/simple" } }, - { name = "cycler" }, - { name = "fonttools", version = "4.63.0", source = { registry = "https://pypi.org/simple" } }, - { name = "kiwisolver", version = "1.5.0", source = { registry = "https://pypi.org/simple" } }, - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } }, - { name = "packaging" }, - { name = "pillow", version = "12.3.0", source = { registry = "https://pypi.org/simple" } }, - { name = "pyparsing" }, - { name = "python-dateutil" }, + { name = "contourpy", version = "1.3.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "cycler", marker = "python_full_version == '3.10.*'" }, + { name = "fonttools", version = "4.63.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "kiwisolver", version = "1.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "packaging", marker = "python_full_version == '3.10.*'" }, + { name = "pillow", version = "12.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "pyparsing", marker = "python_full_version == '3.10.*'" }, + { name = "python-dateutil", marker = "python_full_version == '3.10.*'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", size = 34811233, upload-time = "2026-04-24T00:14:13.539Z" } wheels = [ @@ -3664,16 +3680,16 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ - { name = "contourpy", version = "1.3.3", source = { registry = "https://pypi.org/simple" } }, - { name = "cycler" }, - { name = "fonttools", version = "4.63.0", source = { registry = "https://pypi.org/simple" } }, - { name = "kiwisolver", version = "1.5.0", source = { registry = "https://pypi.org/simple" } }, - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "contourpy", version = "1.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "cycler", marker = "python_full_version >= '3.11'" }, + { name = "fonttools", version = "4.63.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "kiwisolver", version = "1.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "packaging" }, - { name = "pillow", version = "12.3.0", source = { registry = "https://pypi.org/simple" } }, - { name = "pyparsing" }, - { name = "python-dateutil" }, + { name = "packaging", marker = "python_full_version >= '3.11'" }, + { name = "pillow", version = "12.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "pyparsing", marker = "python_full_version >= '3.11'" }, + { name = "python-dateutil", marker = "python_full_version >= '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/49/64/f9a391af28f518b11ad45a8a712353c94a0aefce09d3703200e5c54b610a/matplotlib-3.11.1.tar.gz", hash = "sha256:69647db5746941c793d6e445a4cd349323ffb87d9cc958c2ad84a659b4832d30", size = 32612045, upload-time = "2026-07-18T03:39:46.63Z" } wheels = [ @@ -3745,7 +3761,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" } }, + { name = "markdown-it-py", version = "3.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/19/03/a2ecab526543b152300717cf232bb4bb8605b6edb946c845016fa9c9c9fd/mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5", size = 43542, upload-time = "2024-09-09T20:27:49.564Z" } wheels = [ @@ -3769,7 +3785,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "markdown-it-py", version = "4.2.0", source = { registry = "https://pypi.org/simple" } }, + { name = "markdown-it-py", version = "4.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz", hash = "sha256:a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0", size = 56114, upload-time = "2026-05-13T09:03:38.91Z" } wheels = [ @@ -4006,19 +4022,19 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "boto" }, - { name = "boto3" }, - { name = "cookies" }, - { name = "dicttoxml" }, - { name = "jinja2" }, - { name = "mock" }, - { name = "pyaml" }, - { name = "python-dateutil" }, - { name = "pytz" }, - { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" } }, - { name = "six" }, - { name = "werkzeug" }, - { name = "xmltodict" }, + { name = "boto", marker = "python_full_version <= '3.9'" }, + { name = "boto3", marker = "python_full_version <= '3.9'" }, + { name = "cookies", marker = "python_full_version <= '3.9'" }, + { name = "dicttoxml", marker = "python_full_version <= '3.9'" }, + { name = "jinja2", marker = "python_full_version <= '3.9'" }, + { name = "mock", marker = "python_full_version <= '3.9'" }, + { name = "pyaml", marker = "python_full_version <= '3.9'" }, + { name = "python-dateutil", marker = "python_full_version <= '3.9'" }, + { name = "pytz", marker = "python_full_version <= '3.9'" }, + { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version <= '3.9'" }, + { name = "six", marker = "python_full_version <= '3.9'" }, + { name = "werkzeug", marker = "python_full_version <= '3.9'" }, + { name = "xmltodict", marker = "python_full_version <= '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/cc328bcd0fdc0e4a89f6a042e6a8442494d62908f18e868cef582db11b7e/moto-1.1.13.tar.gz", hash = "sha256:20fff6c5c962156cb4a17a7fb4b3c6ac5cf1c211ca8ee995802db9c5fdf66425", size = 1132192, upload-time = "2017-09-22T17:15:13.332Z" } wheels = [ @@ -4027,7 +4043,7 @@ wheels = [ [package.optional-dependencies] server = [ - { name = "flask" }, + { name = "flask", marker = "python_full_version <= '3.9'" }, ] [[package]] @@ -4038,15 +4054,15 @@ resolution-markers = [ "python_full_version > '3.9' and python_full_version < '3.10'", ] dependencies = [ - { name = "boto3" }, - { name = "botocore" }, - { name = "cryptography" }, - { name = "jinja2" }, - { name = "python-dateutil" }, - { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" } }, - { name = "responses" }, - { name = "werkzeug" }, - { name = "xmltodict" }, + { name = "boto3", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "botocore", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "cryptography", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "jinja2", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "python-dateutil", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "responses", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "werkzeug", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "xmltodict", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b2/3d/1765accbf753dc1ae52f26a2e2ed2881d78c2eb9322c178e45312472e4a0/moto-5.1.22.tar.gz", hash = "sha256:e5b2c378296e4da50ce5a3c355a1743c8d6d396ea41122f5bb2a40f9b9a8cc0e", size = 8547792, upload-time = "2026-03-08T21:06:43.731Z" } wheels = [ @@ -4055,26 +4071,26 @@ wheels = [ [package.optional-dependencies] s3 = [ - { name = "py-partiql-parser" }, - { name = "pyyaml" }, + { name = "py-partiql-parser", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "pyyaml", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, ] server = [ - { name = "antlr4-python3-runtime" }, - { name = "aws-sam-translator", version = "1.103.0", source = { registry = "https://pypi.org/simple" } }, - { name = "aws-xray-sdk" }, - { name = "cfn-lint", version = "1.41.0", source = { registry = "https://pypi.org/simple" } }, - { name = "docker" }, - { name = "flask" }, - { name = "flask-cors" }, - { name = "graphql-core" }, - { name = "joserfc", version = "1.6.8", source = { registry = "https://pypi.org/simple" } }, - { name = "jsonpath-ng" }, - { name = "openapi-spec-validator", version = "0.7.2", source = { registry = "https://pypi.org/simple" } }, - { name = "py-partiql-parser" }, - { name = "pydantic", version = "2.12.4", source = { registry = "https://pypi.org/simple" } }, - { name = "pyparsing" }, - { name = "pyyaml" }, - { name = "setuptools", version = "82.0.1", source = { registry = "https://pypi.org/simple" } }, + { name = "antlr4-python3-runtime", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "aws-sam-translator", version = "1.103.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "aws-xray-sdk", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "cfn-lint", version = "1.41.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "docker", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "flask", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "flask-cors", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "graphql-core", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "joserfc", version = "1.6.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "jsonpath-ng", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "openapi-spec-validator", version = "0.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "py-partiql-parser", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "pydantic", version = "2.12.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "pyparsing", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "pyyaml", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "setuptools", version = "82.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, ] [[package]] @@ -4094,13 +4110,13 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "boto3" }, - { name = "botocore" }, - { name = "cryptography" }, - { name = "requests", version = "2.34.2", source = { registry = "https://pypi.org/simple" } }, - { name = "responses" }, - { name = "werkzeug" }, - { name = "xmltodict" }, + { name = "boto3", marker = "python_full_version >= '3.10'" }, + { name = "botocore", marker = "python_full_version >= '3.10'" }, + { name = "cryptography", marker = "python_full_version >= '3.10'" }, + { name = "requests", version = "2.34.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "responses", marker = "python_full_version >= '3.10'" }, + { name = "werkzeug", marker = "python_full_version >= '3.10'" }, + { name = "xmltodict", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/47/63/d944f387582cc53f53febbff2b3fa36a6d2ed7c1feef8990bf646cfa9cba/moto-5.2.2.tar.gz", hash = "sha256:aac8023a429e125e91c91f8f4730a67b54f518cda587352f7e67252fe3168f75", size = 8678761, upload-time = "2026-06-06T18:57:54.931Z" } wheels = [ @@ -4109,24 +4125,24 @@ wheels = [ [package.optional-dependencies] s3 = [ - { name = "py-partiql-parser" }, - { name = "pyyaml" }, + { name = "py-partiql-parser", marker = "python_full_version >= '3.10'" }, + { name = "pyyaml", marker = "python_full_version >= '3.10'" }, ] server = [ - { name = "antlr4-python3-runtime" }, - { name = "aws-xray-sdk" }, - { name = "cfn-lint", version = "1.53.2", source = { registry = "https://pypi.org/simple" } }, - { name = "docker" }, - { name = "flask" }, - { name = "flask-cors" }, - { name = "graphql-core" }, - { name = "joserfc", version = "1.7.4", source = { registry = "https://pypi.org/simple" } }, - { name = "jsonpath-ng" }, - { name = "openapi-spec-validator", version = "0.9.0", source = { registry = "https://pypi.org/simple" } }, - { name = "py-partiql-parser" }, - { name = "pyparsing" }, - { name = "pyyaml" }, - { name = "setuptools", version = "83.0.0", source = { registry = "https://pypi.org/simple" } }, + { name = "antlr4-python3-runtime", marker = "python_full_version >= '3.10'" }, + { name = "aws-xray-sdk", marker = "python_full_version >= '3.10'" }, + { name = "cfn-lint", version = "1.53.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "docker", marker = "python_full_version >= '3.10'" }, + { name = "flask", marker = "python_full_version >= '3.10'" }, + { name = "flask-cors", marker = "python_full_version >= '3.10'" }, + { name = "graphql-core", marker = "python_full_version >= '3.10'" }, + { name = "joserfc", version = "1.7.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "jsonpath-ng", marker = "python_full_version >= '3.10'" }, + { name = "openapi-spec-validator", version = "0.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "py-partiql-parser", marker = "python_full_version >= '3.10'" }, + { name = "pyparsing", marker = "python_full_version >= '3.10'" }, + { name = "pyyaml", marker = "python_full_version >= '3.10'" }, + { name = "setuptools", version = "83.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] [[package]] @@ -4332,10 +4348,10 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "jupyter-client", version = "8.6.3", source = { registry = "https://pypi.org/simple" } }, - { name = "jupyter-core", version = "5.8.1", source = { registry = "https://pypi.org/simple" } }, - { name = "nbformat" }, - { name = "traitlets" }, + { name = "jupyter-client", version = "8.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "jupyter-core", version = "5.8.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "nbformat", marker = "python_full_version < '3.10'" }, + { name = "traitlets", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/87/66/7ffd18d58eae90d5721f9f39212327695b749e23ad44b3881744eaf4d9e8/nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193", size = 62424, upload-time = "2024-12-19T10:32:27.164Z" } wheels = [ @@ -4359,10 +4375,10 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "jupyter-client", version = "8.9.1", source = { registry = "https://pypi.org/simple" } }, - { name = "jupyter-core", version = "5.9.1", source = { registry = "https://pypi.org/simple" } }, - { name = "nbformat" }, - { name = "traitlets" }, + { name = "jupyter-client", version = "8.9.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "jupyter-core", version = "5.9.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "nbformat", marker = "python_full_version >= '3.10'" }, + { name = "traitlets", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/28/a5/b3bae4b590c0cbcada2c63a34f7580024e834a8ba213e949a2f906705787/nbclient-0.11.0.tar.gz", hash = "sha256:04a134a5b087f2c5887f228aca155db50169b8cd9334dee6942c8e927e56081a", size = 62535, upload-time = "2026-06-05T07:52:41.746Z" } wheels = [ @@ -4724,9 +4740,9 @@ resolution-markers = [ "python_full_version > '3.9' and python_full_version < '3.10'", ] dependencies = [ - { name = "jsonschema", version = "4.25.1", source = { registry = "https://pypi.org/simple" } }, - { name = "jsonschema-specifications" }, - { name = "rfc3339-validator" }, + { name = "jsonschema", version = "4.25.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "jsonschema-specifications", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "rfc3339-validator", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8b/f3/5507ad3325169347cd8ced61c232ff3df70e2b250c49f0fe140edb4973c6/openapi_schema_validator-0.6.3.tar.gz", hash = "sha256:f37bace4fc2a5d96692f4f8b31dc0f8d7400fd04f3a937798eaf880d425de6ee", size = 11550, upload-time = "2025-01-10T18:08:22.268Z" } wheels = [ @@ -4750,12 +4766,12 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "jsonschema", version = "4.26.0", source = { registry = "https://pypi.org/simple" } }, - { name = "jsonschema-specifications" }, - { name = "pydantic", version = "2.13.4", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic-settings" }, - { name = "referencing", version = "0.37.0", source = { registry = "https://pypi.org/simple" } }, - { name = "rfc3339-validator" }, + { name = "jsonschema", version = "4.26.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "jsonschema-specifications", marker = "python_full_version >= '3.10'" }, + { name = "pydantic", version = "2.13.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pydantic-settings", marker = "python_full_version >= '3.10'" }, + { name = "referencing", version = "0.37.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "rfc3339-validator", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/98/e8/ab3f27dbca54ec645f7fab714b640907d5d36c2ebb07e87eebd30bd5c81b/openapi_schema_validator-0.9.0.tar.gz", hash = "sha256:b72db64315b89d21834cd3ffef37e3e6893bc876327be2d366e8424b1029afd3", size = 24686, upload-time = "2026-04-27T17:31:27.606Z" } wheels = [ @@ -4770,10 +4786,10 @@ resolution-markers = [ "python_full_version > '3.9' and python_full_version < '3.10'", ] dependencies = [ - { name = "jsonschema", version = "4.25.1", source = { registry = "https://pypi.org/simple" } }, - { name = "jsonschema-path", version = "0.3.4", source = { registry = "https://pypi.org/simple" } }, - { name = "lazy-object-proxy" }, - { name = "openapi-schema-validator", version = "0.6.3", source = { registry = "https://pypi.org/simple" } }, + { name = "jsonschema", version = "4.25.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "jsonschema-path", version = "0.3.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "lazy-object-proxy", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "openapi-schema-validator", version = "0.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/82/af/fe2d7618d6eae6fb3a82766a44ed87cd8d6d82b4564ed1c7cfb0f6378e91/openapi_spec_validator-0.7.2.tar.gz", hash = "sha256:cc029309b5c5dbc7859df0372d55e9d1ff43e96d678b9ba087f7c56fc586f734", size = 36855, upload-time = "2025-06-07T14:48:56.299Z" } wheels = [ @@ -4797,12 +4813,12 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "jsonschema", version = "4.26.0", source = { registry = "https://pypi.org/simple" } }, - { name = "jsonschema-path", version = "0.5.0", source = { registry = "https://pypi.org/simple" } }, - { name = "lazy-object-proxy" }, - { name = "openapi-schema-validator", version = "0.9.0", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic", version = "2.13.4", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic-settings" }, + { name = "jsonschema", version = "4.26.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "jsonschema-path", version = "0.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "lazy-object-proxy", marker = "python_full_version >= '3.10'" }, + { name = "openapi-schema-validator", version = "0.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pydantic", version = "2.13.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pydantic-settings", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8f/d2/640b5149cd5688bc0ad1fdbb4df6a2f7b84a093c8d787c27d566132f8b8b/openapi_spec_validator-0.9.0.tar.gz", hash = "sha256:6d648cff6490ebb799dcfe273792f2941c050158854c721f086599d845da78b8", size = 1756839, upload-time = "2026-05-20T09:23:18.871Z" } wheels = [ @@ -4837,11 +4853,11 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version != '3.10.*'" }, + { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, - { name = "python-dateutil" }, - { name = "pytz" }, - { name = "tzdata" }, + { name = "python-dateutil", marker = "python_full_version < '3.11'" }, + { name = "pytz", marker = "python_full_version < '3.11'" }, + { name = "tzdata", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } wheels = [ @@ -4903,8 +4919,8 @@ wheels = [ [package.optional-dependencies] output-formatting = [ - { name = "jinja2" }, - { name = "tabulate", version = "0.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version != '3.10.*'" }, + { name = "jinja2", marker = "python_full_version < '3.11'" }, + { name = "tabulate", version = "0.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "tabulate", version = "0.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, ] @@ -4924,10 +4940,10 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "python-dateutil" }, - { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, + { name = "python-dateutil", marker = "python_full_version >= '3.11'" }, + { name = "tzdata", marker = "(python_full_version >= '3.11' and sys_platform == 'emscripten') or (python_full_version >= '3.11' and sys_platform == 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/be/4f/5f3422a2afec5ffc46308b79e53291365a93748b498ac2e58bead0197916/pandas-3.0.5.tar.gz", hash = "sha256:dca3734d6ab7c906e6730f0788b0a1dbb9f2467731f9711f77995c8e9d62d712", size = 4658219, upload-time = "2026-07-22T22:19:28.819Z" } wheels = [ @@ -4976,8 +4992,8 @@ wheels = [ [package.optional-dependencies] output-formatting = [ - { name = "jinja2" }, - { name = "tabulate", version = "0.10.0", source = { registry = "https://pypi.org/simple" } }, + { name = "jinja2", marker = "python_full_version >= '3.11'" }, + { name = "tabulate", version = "0.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] [[package]] @@ -5045,7 +5061,7 @@ name = "pexpect" version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ptyprocess" }, + { name = "ptyprocess", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } wheels = [ @@ -5327,7 +5343,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "polars-runtime-32", version = "1.36.1", source = { registry = "https://pypi.org/simple" } }, + { name = "polars-runtime-32", version = "1.36.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9f/dc/56f2a90c79a2cb13f9e956eab6385effe54216ae7a2068b3a6406bae4345/polars-1.36.1.tar.gz", hash = "sha256:12c7616a2305559144711ab73eaa18814f7aa898c522e7645014b68f1432d54c", size = 711993, upload-time = "2025-12-10T01:14:53.033Z" } wheels = [ @@ -5351,7 +5367,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "polars-runtime-32", version = "1.43.1", source = { registry = "https://pypi.org/simple" } }, + { name = "polars-runtime-32", version = "1.43.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/32/79/720f4901230992f359653717e7cc3596731ed36e1a27be351d128ee0c3b7/polars-1.43.1.tar.gz", hash = "sha256:cb07ff3ad61c7b28043e6176e5fdb04a294346920b7f033deeb84116b4911883", size = 750058, upload-time = "2026-07-27T12:07:58.288Z" } wheels = [ @@ -5413,11 +5429,11 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "cfgv", version = "3.4.0", source = { registry = "https://pypi.org/simple" } }, - { name = "identify", version = "2.6.15", source = { registry = "https://pypi.org/simple" } }, - { name = "nodeenv" }, - { name = "pyyaml" }, - { name = "virtualenv" }, + { name = "cfgv", version = "3.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "identify", version = "2.6.15", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "nodeenv", marker = "python_full_version < '3.10'" }, + { name = "pyyaml", marker = "python_full_version < '3.10'" }, + { name = "virtualenv", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ff/29/7cf5bbc236333876e4b41f56e06857a87937ce4bf91e117a6991a2dbb02a/pre_commit-4.3.0.tar.gz", hash = "sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16", size = 193792, upload-time = "2025-08-09T18:56:14.651Z" } wheels = [ @@ -5441,11 +5457,11 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "cfgv", version = "3.5.0", source = { registry = "https://pypi.org/simple" } }, - { name = "identify", version = "2.6.19", source = { registry = "https://pypi.org/simple" } }, - { name = "nodeenv" }, - { name = "pyyaml" }, - { name = "virtualenv" }, + { name = "cfgv", version = "3.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "identify", version = "2.6.19", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "nodeenv", marker = "python_full_version >= '3.10'" }, + { name = "pyyaml", marker = "python_full_version >= '3.10'" }, + { name = "virtualenv", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/25/3a/ddb78f32a0814e66b18a099377a106a2dcdce92d86a034d69d65df9b256e/pre_commit-4.6.1.tar.gz", hash = "sha256:03e809865c7d178b9979d06c761fcbfe6808fdaded8581a745bb110e52050421", size = 198646, upload-time = "2026-07-21T20:56:58.225Z" } wheels = [ @@ -5461,7 +5477,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "wcwidth" }, + { name = "wcwidth", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } wheels = [ @@ -5485,7 +5501,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "wcwidth" }, + { name = "wcwidth", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7d/ea/39b988c938f75cb75d7045b5c69f8bfed47ee2152c8837fb403de29d6fb8/prompt_toolkit-3.0.53.tar.gz", hash = "sha256:9ec8a0ad96d5c56148b3f914aa79c1564c3fde5d2e6b876e7bc327e353cf8fa6", size = 435492, upload-time = "2026-07-26T20:56:14.758Z" } wheels = [ @@ -5825,7 +5841,7 @@ name = "pyaml" version = "26.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyyaml" }, + { name = "pyyaml", marker = "python_full_version <= '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/15/6a/acfdf17de0d6947b419da8696e02b781b18de2cf49e0472298b50e1f0711/pyaml-26.7.0.tar.gz", hash = "sha256:11cda3a796efc6dbce0d56836be56cfd26289dad07bcd78e9904086729929c93", size = 30669, upload-time = "2026-07-04T00:34:38.532Z" } wheels = [ @@ -5990,10 +6006,10 @@ resolution-markers = [ "python_full_version > '3.9' and python_full_version < '3.10'", ] dependencies = [ - { name = "annotated-types", version = "0.7.0", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic-core", version = "2.41.5", source = { registry = "https://pypi.org/simple" } }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, + { name = "annotated-types", version = "0.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "pydantic-core", version = "2.41.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "typing-extensions", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, + { name = "typing-inspection", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/96/ad/a17bc283d7d81837c061c49e3eaa27a45991759a1b7eae1031921c6bd924/pydantic-2.12.4.tar.gz", hash = "sha256:0f8cb9555000a4b5b617f66bfd2566264c4984b27589d3b845685983e8ea85ac", size = 821038, upload-time = "2025-11-05T10:50:08.59Z" } wheels = [ @@ -6017,10 +6033,10 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "annotated-types", version = "0.8.0", source = { registry = "https://pypi.org/simple" } }, - { name = "pydantic-core", version = "2.46.4", source = { registry = "https://pypi.org/simple" } }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, + { name = "annotated-types", version = "0.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pydantic-core", version = "2.46.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, + { name = "typing-inspection", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" } wheels = [ @@ -6035,7 +6051,7 @@ resolution-markers = [ "python_full_version > '3.9' and python_full_version < '3.10'", ] dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } wheels = [ @@ -6178,7 +6194,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } wheels = [ @@ -6308,9 +6324,9 @@ name = "pydantic-settings" version = "2.14.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pydantic", version = "2.13.4", source = { registry = "https://pypi.org/simple" } }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, + { name = "pydantic", version = "2.13.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "python-dotenv", marker = "python_full_version >= '3.10'" }, + { name = "typing-inspection", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5c/b5/8f48e906c3e0205276e8bd8cb7512217a87b2685304d64be27cad5b3019f/pydantic_settings-2.14.2.tar.gz", hash = "sha256:c19dd64b19097f1de80184f0cc7b0272a13ae6e170cbf240a3e27e381ed14a5f", size = 237700, upload-time = "2026-06-19T13:44:56.324Z" } wheels = [ @@ -6347,8 +6363,8 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" } }, - { name = "pyyaml" }, + { name = "markdown", version = "3.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "pyyaml", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9e/26/d1015444da4d952a1ca487a236b522eb979766f0295a0bd0c5fc089989a9/pymdown_extensions-10.21.3.tar.gz", hash = "sha256:72cfcf55f07aea0d4af2c4f11dd4e52466ddfb1bb819673146398e0bd3a77354", size = 854140, upload-time = "2026-05-13T12:57:32.267Z" } wheels = [ @@ -6372,8 +6388,8 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "markdown", version = "3.10.2", source = { registry = "https://pypi.org/simple" } }, - { name = "pyyaml" }, + { name = "markdown", version = "3.10.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "pyyaml", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/21/a9/5f0c535ba3b08fe09270c16808e053a968868242ecbd5676d4e3a488bf28/pymdown_extensions-11.0.1.tar.gz", hash = "sha256:dd2905ae6fc5b75582fafb139a1266ffc754705efa902aa50067fa7ff4f94ec0", size = 857113, upload-time = "2026-07-02T17:59:22.955Z" } wheels = [ @@ -6398,13 +6414,13 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "exceptiongroup" }, - { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" } }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "pygments" }, - { name = "tomli" }, + { name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.10'" }, + { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "packaging", marker = "python_full_version < '3.10'" }, + { name = "pluggy", marker = "python_full_version < '3.10'" }, + { name = "pygments", marker = "python_full_version < '3.10'" }, + { name = "tomli", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } wheels = [ @@ -6428,13 +6444,13 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" } }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "pygments" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" }, + { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "packaging", marker = "python_full_version >= '3.10'" }, + { name = "pluggy", marker = "python_full_version >= '3.10'" }, + { name = "pygments", marker = "python_full_version >= '3.10'" }, + { name = "tomli", marker = "python_full_version == '3.10.*'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } wheels = [ @@ -6450,7 +6466,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "werkzeug" }, + { name = "werkzeug", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f1/d8/def15ba33bd696dd72dd4562a5287c0cba4d18a591eeb82e0b08ab385afc/pytest_httpserver-1.1.3.tar.gz", hash = "sha256:af819d6b533f84b4680b9416a5b3f67f1df3701f1da54924afd4d6e4ba5917ec", size = 68870, upload-time = "2025-04-10T08:17:15.6Z" } wheels = [ @@ -6474,7 +6490,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "werkzeug" }, + { name = "werkzeug", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/17/ad187f46998814014f7cda309de700b87c0eb4b2e111e18bc8c819be7116/pytest_httpserver-1.1.5.tar.gz", hash = "sha256:dc3d82e1fe00e491829d8939c549bf4bd9b39a260f87113c619b9d517c2f8ff1", size = 70974, upload-time = "2026-02-14T13:27:23.412Z" } wheels = [ @@ -6750,9 +6766,9 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "attrs" }, - { name = "rpds-py", version = "0.27.1", source = { registry = "https://pypi.org/simple" } }, - { name = "typing-extensions" }, + { name = "attrs", marker = "python_full_version < '3.10'" }, + { name = "rpds-py", version = "0.27.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "typing-extensions", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } wheels = [ @@ -6776,10 +6792,10 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "attrs" }, - { name = "rpds-py", version = "0.30.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "attrs", marker = "python_full_version >= '3.10'" }, + { name = "rpds-py", version = "0.30.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, { name = "rpds-py", version = "2026.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions", marker = "python_full_version >= '3.10' and python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } wheels = [ @@ -7069,10 +7085,10 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" } }, + { name = "certifi", marker = "python_full_version < '3.10'" }, + { name = "charset-normalizer", marker = "python_full_version < '3.10'" }, + { name = "idna", marker = "python_full_version < '3.10'" }, + { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ @@ -7096,10 +7112,10 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3", version = "2.7.0", source = { registry = "https://pypi.org/simple" } }, + { name = "certifi", marker = "python_full_version >= '3.10'" }, + { name = "charset-normalizer", marker = "python_full_version >= '3.10'" }, + { name = "idna", marker = "python_full_version >= '3.10'" }, + { name = "urllib3", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } wheels = [ @@ -7111,10 +7127,10 @@ name = "responses" version = "0.26.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyyaml" }, - { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "pyyaml", marker = "python_full_version > '3.9'" }, + { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, { name = "requests", version = "2.34.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "urllib3", version = "1.26.20", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version > '3.9' and python_full_version < '3.10'" }, { name = "urllib3", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f0/1a/4af3e6d659394b809838490b144e4ab8d7ed3b9fecc7ca78f5d2f79b1a3d/responses-0.26.2.tar.gz", hash = "sha256:9c9259b46a8349197edebf43cfa68a87e1a2802ef503ff8b2fecbabc0b45afd8", size = 84030, upload-time = "2026-07-03T16:44:50.325Z" } @@ -7127,7 +7143,7 @@ name = "rfc3339-validator" version = "0.1.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, + { name = "six", marker = "python_full_version > '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } wheels = [ @@ -7593,9 +7609,9 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "aiobotocore" }, - { name = "aiohttp", version = "3.13.5", source = { registry = "https://pypi.org/simple" } }, - { name = "fsspec", version = "2025.10.0", source = { registry = "https://pypi.org/simple" } }, + { name = "aiobotocore", marker = "python_full_version < '3.10'" }, + { name = "aiohttp", version = "3.13.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "fsspec", version = "2025.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bb/ee/7cf7de3b17ef6db10b027cc9f8a1108ceb6333e267943e666a35882b1474/s3fs-2025.10.0.tar.gz", hash = "sha256:e8be6cddc77aceea1681ece0f472c3a7f8ef71a0d2acddb1cc92bb6afa3e9e4f", size = 80383, upload-time = "2025-10-30T15:06:04.647Z" } wheels = [ @@ -7619,9 +7635,9 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "aiobotocore" }, - { name = "aiohttp", version = "3.14.3", source = { registry = "https://pypi.org/simple" } }, - { name = "fsspec", version = "2025.12.0", source = { registry = "https://pypi.org/simple" } }, + { name = "aiobotocore", marker = "python_full_version >= '3.10'" }, + { name = "aiohttp", version = "3.14.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "fsspec", version = "2025.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cf/26/fff848df6a76d6fec20208e61548244639c46a741e296244c3404d6e7df0/s3fs-2025.12.0.tar.gz", hash = "sha256:8612885105ce14d609c5b807553f9f9956b45541576a17ff337d9435ed3eb01f", size = 81217, upload-time = "2025-12-03T15:34:04.754Z" } wheels = [ @@ -7649,7 +7665,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" } }, + { name = "numpy", version = "2.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ae/00/48c2f661e2816ccf2ecd77982f6605b2950afe60f60a52b4cbbc2504aa8f/scipy-1.13.1.tar.gz", hash = "sha256:095a87a0312b08dfd6a6155cbbd310a8c51800fc931b8c0b84003014b874ed3c", size = 57210720, upload-time = "2024-05-23T03:29:26.079Z" } wheels = [ @@ -7687,7 +7703,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" } wheels = [ @@ -7748,7 +7764,7 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" } }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" } wheels = [ @@ -7827,7 +7843,7 @@ resolution-markers = [ "python_full_version >= '3.12' and python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ - { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" } }, + { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a7/25/c2700dfaf6442b4effaa91af24ebce5dc9d31bb4a69706313aae70d72cd0/scipy-1.18.0.tar.gz", hash = "sha256:67b2ad2ad54c72ca6d04975a9b2df8c3638c34ddd5b28738e94fc2b57929d378", size = 30774447, upload-time = "2026-06-19T15:01:43.456Z" } wheels = [ @@ -8009,7 +8025,7 @@ name = "sympy" version = "1.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "mpmath" }, + { name = "mpmath", marker = "python_full_version > '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } wheels = [ @@ -8093,7 +8109,7 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "webencodings" }, + { name = "webencodings", marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } wheels = [ @@ -8117,7 +8133,7 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "webencodings" }, + { name = "webencodings", marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a3/ae/2ca4913e5c0f09781d75482874c3a95db9105462a92ddd303c7d285d3df2/tinycss2-1.5.1.tar.gz", hash = "sha256:d339d2b616ba90ccce58da8495a78f46e55d4d25f9fd71dfd526f07e7d53f957", size = 88195, upload-time = "2025-11-23T10:29:10.082Z" } wheels = [ @@ -8218,7 +8234,7 @@ name = "typing-inspection" version = "0.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version > '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } wheels = [ @@ -8450,9 +8466,9 @@ resolution-markers = [ "python_full_version <= '3.9'", ] dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache", version = "0.4.1", source = { registry = "https://pypi.org/simple" } }, + { name = "idna", marker = "python_full_version < '3.10'" }, + { name = "multidict", marker = "python_full_version < '3.10'" }, + { name = "propcache", version = "0.4.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } wheels = [ @@ -8604,9 +8620,9 @@ resolution-markers = [ "python_full_version == '3.10.*'", ] dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache", version = "0.5.2", source = { registry = "https://pypi.org/simple" } }, + { name = "idna", marker = "python_full_version >= '3.10'" }, + { name = "multidict", marker = "python_full_version >= '3.10'" }, + { name = "propcache", version = "0.5.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/31/33/ebe9e3d1f86c7a0b51094c0a146392045ca1631d2664889539dec8088a33/yarl-1.24.5.tar.gz", hash = "sha256:e81b83143bee16329c23db3c1b2d82b29892fcbcb849186d2f6e98a5abe9a57f", size = 228679, upload-time = "2026-07-20T02:07:45.435Z" } wheels = [