diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..9bb8f0d --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,9 @@ +Fixes: #--- + +## Quality Assurance Checklist +- [ ] This PR is opened against the dev branch. +- [ ] Code follows the project style guidelines and passes flake8 linting. +- [ ] Type annotations are correct and pass mypy static analysis. +- [ ] All existing and new unittests pass locally. + +## Proposed Changes \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index b939cba..338433c 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -7,7 +7,6 @@ # documentation. name: Upload Python Package - on: release: types: [published] @@ -25,7 +24,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v3 with: - python-version: '3.x' + python-version: '3.13' - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index 1ea85c1..ab8bac7 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -3,6 +3,9 @@ name: Package test +permissions: + contents: read + on: push: branches: [ "main", "dev"] diff --git a/.github/workflows/wiki.yml b/.github/workflows/wiki.yml index 219ee84..416dc0f 100644 --- a/.github/workflows/wiki.yml +++ b/.github/workflows/wiki.yml @@ -1,7 +1,7 @@ name: Publish wiki on: push: - branches: [revision] + branches: [main] paths: - docs/** - .github/workflows/publish-wiki.yml @@ -13,20 +13,30 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + - uses: actions/setup-node@v6 + with: + node-version: "latest" + - name: render badge images + run: | + cd docs/_static + npm ci + node create_badges.js + - uses: actions/setup-python@v6 with: python-version: '3.13' - name: build wiki run: | - cd docs/docs_source - pip install -r requirements.txt - make markdown + pip install -e . + pip install -r docs/docs_source/requirements.txt + make -C docs/docs_source markdown - name: move markdown pages run: | - cd .. - mkdir API - mv docs_source/build/markdown ./API - rm -r docs_source + mkdir -p docs/API + rm docs/docs_source/build/markdown/index.md + mv docs/docs_source/build/markdown/* docs/API/ + # remove source_dir + rm -r docs/docs_source - uses: Andrew-Chen-Wang/github-wiki-action@v4 with: path: docs/ \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7075f53..7c71191 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ __pycache__/ # C extensions *.so +*.C # unignore built documentation @@ -166,5 +167,5 @@ cython_debug/ #.idea/ .DS_Store - +node_modules/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index c1f1ad4..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,13 +0,0 @@ -image: python:latest - -deploy: - variables: - TWINE_USERNAME: gitlab-ci-token - TWINE_PASSWORD: $CI_JOB_TOKEN - script: - - pip install -r requirements.txt - - python -m build - - python -m twine upload --repository-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi dist/* - only: - refs: - - tags \ No newline at end of file diff --git a/.readthedocs.yml b/.readthedocs.yml deleted file mode 100644 index d786e48..0000000 --- a/.readthedocs.yml +++ /dev/null @@ -1,22 +0,0 @@ -# Read the Docs configuration file -# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details - -# Required -version: 2 - -# Set the OS, Python version, and other tools you might need -build: - os: ubuntu-24.04 - tools: - python: "3.13" - -# Build documentation in the "docs/" directory with Sphinx -sphinx: - configuration: docs/source/conf.py - -python: - install: - - method: pip - path: . - - requirements: docs/requirements.txt - \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dcc101..3a363d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +# Version 1.2 +- Required Python version: >= 3.12 +- The package now follows SPEC0 +- All functions can be now be imported from the top-level namespace +- Adding descriptive statistics and plotting functions +- Added support for the GRM and GPCM models (polytomous response variables) +- Added `SkewNormalPrior` and `EmpiricalPrior` for Bayesian ability estimation +- Added support for Content Balancing and Exposure Control +- The package is now also published on conda-forge + +*Note*: We have tried our best to eliminate breaking changes. +But still, please be careful when updating to this version. # Version 1.1.6 - Bug Fig #49 (optimization interval issue in BayesModal) diff --git a/README.md b/README.md index c67cb15..a022d00 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,6 @@ # adaptivetesting -[![SPEC 0 — Minimum Supported Dependencies](docs/source/_static/SPEC-0.svg)](https://scientific-python.org/specs/spec-0000/) - - - + **An open-source Python package for simplified, customizable Computerized Adaptive Testing (CAT) using Bayesian methods.** @@ -13,12 +10,14 @@ - **Bayesian Methods**: Built-in support for Bayesian ability estimation with customizable priors - **Flexible Architecture**: Object-oriented design with abstract classes for easy extension -- **Item Response Theory**: Full support for 1PL, 2PL, 3PL, and 4PL models +- **Item Response Theory**: Full support for 1PL, 2PL, 3PL, and 4PL models, GRM, GPCM - **Multiple Estimators**: - Maximum Likelihood Estimation (MLE) - Bayesian Modal Estimation (BM) - Expected A Posteriori (EAP) -- **Item Selection Strategies**: Kaximum information criterion and Urry's rule +- **Item Selection Strategies**: Maximum information criterion +- **Content Balancing**: Maximum Priority Index, Weighted Penalty Model +- **Exposure Control**: Randomesque Item Selection, Maximum Priority Index - **Simulation Framework**: Comprehensive tools for CAT simulation and evaluation - **Real-world Application**: Direct transition from simulation to production testing - **Stopping Criteria**: Support for standard error and test length criteria @@ -38,282 +37,6 @@ For the latest development version: pip install git+https://github.com/condecon/adaptivetesting ``` -## Requirements - -- Python >= 3.10 -- NumPy >= 2.0.0 -- Pandas >= 2.2.0 -- SciPy >= 1.15.0 -- tqdm >= 4.67.1 - -## Quick Start - -### Basic Example: Setting Up an Adaptive Test - -```python -from adaptivetesting.models import ItemPool, TestItem -from adaptivetesting.implementations import TestAssembler -from adaptivetesting.math.estimators import BayesModal, NormalPrior -from adaptivetesting.simulation import Simulation, StoppingCriterion, ResultOutputFormat -import pandas as pd - -# Create item pool from DataFrame -items_data = pd.DataFrame({ - "a": [1.32, 1.07, 0.84, 1.19, 0.95], # discrimination - "b": [-0.63, 0.18, -0.84, 0.41, -0.25], # difficulty - "c": [0.17, 0.10, 0.19, 0.15, 0.12], # guessing - "d": [0.87, 0.93, 1.0, 0.89, 0.94] # upper asymptote -}) -item_pool = ItemPool.load_from_dataframe(items_data) - -# Set up adaptive test -adaptive_test = TestAssembler( - item_pool=item_pool, - simulation_id="sim_001", - participant_id="participant_001", - ability_estimator=BayesModal, - estimator_args={"prior": NormalPrior(mean=0, sd=1)}, - true_ability_level=0.5, # For simulation - simulation=True -) - -# Run simulation -simulation = Simulation( - test=adaptive_test, - test_result_output=ResultOutputFormat.CSV -) - -simulation.simulate( - criterion=StoppingCriterion.SE, - value=0.3 # Stop when standard error <= 0.3 -) - -# Save results -simulation.save_test_results() -``` - -### Custom Prior Example - -```python -from adaptivetesting.math.estimators import CustomPrior -from scipy.stats import t - -# Create custom t prior -custom_prior = CustomPrior(t, 100) - -# Use in estimator -adaptive_test = TestAssembler( - item_pool=item_pool, - simulation_id="custom_prior_sim", - participant_id="participant_002", - ability_estimator=BayesModal, - estimator_args={"prior": custom_prior}, - true_ability_level=0.0, - simulation=True -) -``` - -### Real-world Testing (Non-simulation) with PsychoPy - -```python -# setup item pool -# the item pool is retrieved from the PREVIC -# https://github.com/manuelbohn/previc/tree/main/saves -import pandas as pd -from adaptivetesting.models import ItemPool -from psychopy import visual, event -from psychopy.hardware import keyboard -from adaptivetesting.implementations import TestAssembler -from adaptivetesting.models import AdaptiveTest, ItemPool, TestItem -from adaptivetesting.data import CSVContext -from adaptivetesting.math.estimators import ExpectedAPosteriori, CustomPrior -from adaptivetesting.math.item_selection import maximum_information_criterion -from scipy.stats import t -import pandas as pd - -previc_item_pool = pd.read_csv("item_pool.csv") -# add item column -previc_item_pool["id"] = list(range(1, 90)) -previc_item_pool.head() - - -item_pool = ItemPool.load_from_list( - b=previc_item_pool["Difficulty"], - ids=previc_item_pool["id"] -) - -# Create adaptive test -adaptive_test: AdaptiveTest = TestAssembler( - item_pool=item_pool, - simulation_id="example", - participant_id="dummy", - ability_estimator=BayesModal, - estimator_args={ - "prior": CustomPrior(t, 100), - "optimization_interval":(-10, 10) - }, - item_selector=maximum_information_criterion, - simulation=False, - debug=False -) - -# ==================== -# Setup PsychoPy -# ==================== - -# general setup -win = visual.Window([800, 600], - monitor="testMonitor", - units="deg", - fullscr=False) - -# init keyboard -keyboard.Keyboard() - -## FIX THIS - -# define function to get user input -def get_response(item: TestItem) -> int: - # select corresponding word from item pool data frame - stimuli: str = previc_item_pool[previc_item_pool["id"] == item.id]["word"].values[0] - - # create text box and display stimulus - text_box = visual.TextBox2(win=win, - text=stimuli, - alignment="center", - size=24) - # draw text - text_box.draw() - # update window - win.flip() - - # wait for pressed keys - while True: - keys = event.getKeys() - # if keys are not None - if keys: - # if the right arrow keys is pressed - # return 1 - if keys[0] == "right": - return 1 - # if the left arrow keys is pressed - # return 0 - if keys[0] == "left": - return 0 - - -# override adaptive test default function -adaptive_test.get_response = get_response - -# start adaptive test -while True: - adaptive_test.run_test_once() - - # check stopping criterion - if adaptive_test.standard_error <= 0.4: - break - - # end test if all items have been shown - if len(adaptive_test.item_pool.test_items) == 0: - break - -# save test results -data_context = CSVContext( - adaptive_test.simulation_id, - adaptive_test.participant_id -) - -data_context.save(adaptive_test.test_results) -``` - -## Package Structure - -The package is organized into several key modules: - -- **`adaptivetesting.models`**: Core classes including `AdaptiveTest`, `ItemPool`, and `TestItem` -- **`adaptivetesting.implementations`**: Ready-to-use test implementations like `TestAssembler` -- **`adaptivetesting.math`**: Mathematical functions for IRT, ability estimation, and item selection -- **`adaptivetesting.simulation`**: Simulation framework and result management -- **`adaptivetesting.data`**: Data management utilities for CSV and pickle formats -- **`adaptivetesting.services`**: Abstract interfaces and protocols - -## Advanced Features - -### Multiple Stopping Criteria - -```python -simulation.simulate( - criterion=[StoppingCriterion.SE, StoppingCriterion.LENGTH], - value=[0.3, 20] # Stop at SE ≤ 0.3 OR length ≥ 20 items -) -``` - -### Pretest Phase - -```python -adaptive_test = TestAssembler( - item_pool=item_pool, - simulation_id="pretest_sim", - participant_id="participant_003", - ability_estimator=BayesModal, - estimator_args={"prior": NormalPrior(0, 1)}, - pretest=True, - pretest_seed=42, - simulation=True -) -``` - -### Custom Item Selection - -```python -from adaptivetesting.math.item_selection import maximum_information_criterion - -adaptive_test = TestAssembler( - item_pool=item_pool, - simulation_id="custom_selection", - participant_id="participant_004", - ability_estimator=BayesModal, - estimator_args={"prior": NormalPrior(0, 1)}, - item_selector=maximum_information_criterion, - item_selector_args={"additional_param": "value"}, - simulation=True -) -``` - -### Custom Optimization Interval -```python -adaptive_test = TestAssembler( - item_pool=item_pool, - simulation_id="pretest_sim", - participant_id="participant_003", - ability_estimator=BayesModal, - estimator_args={ - "prior": NormalPrior(0, 1), - "optimization_interval": (-5, 5)}, - pretest_seed=42, - simulation=True -) -``` - -## Documentation - -Full documentation is available in the `docs/` directory: - -- [API Reference](docs/readme.md) -- [Models Module](docs/models.md) -- [Math Module](docs/math.md) -- [Implementation Examples](docs/implementations.md) -- [Simulation Guide](docs/simulation.md) - -## Testing - -The package includes comprehensive tests. Run them using: - -```bash -uv sync -uv run python -m unittest -``` - ## Contributing We welcome contributions! Please see our [GitHub repository](https://github.com/condecon/adaptivetesting) for: diff --git a/adaptivetesting/__init__.py b/adaptivetesting/__init__.py index fc88426..88b1811 100644 --- a/adaptivetesting/__init__.py +++ b/adaptivetesting/__init__.py @@ -12,18 +12,21 @@ from .implementations.__default_implementation import DefaultImplementation from .implementations.__pre_test import PreTest from .implementations.__semi_implementation import SemiAdaptiveImplementation -from .implementations.__test_assembler import TestAssembler +from .implementations.__test_assembler import TestAssembler, ContentBalancingArgs, ExposureControlArgs from .math.__gen_response_pattern import generate_response_pattern from .math.estimators.__ml_estimation import MLEstimator from .math.estimators.__bayes_modal_estimation import BayesModal from .math.estimators.__expect_a_posteriori import ExpectedAPosteriori -from .math.estimators.__prior import Prior, NormalPrior, CustomPrior, CustomPriorException +from .math.estimators.__prior import Prior, NormalPrior, CustomPrior, CustomPriorException, SkewNormalPrior, EmpiricalPrior from .math.estimators.__functions.__estimators import probability_y0, probability_y1, maximize_likelihood_function, likelihood from .math.estimators.__functions.__bayes import maximize_posterior from .math.estimators.__test_information import test_information_function, item_information_function, prior_information_function from .math.item_selection.__maximum_information_criterion import maximum_information_criterion from .math.item_selection.__urrys_rule import urrys_rule +from .math.content_balancing.__weighted_penalty_model import WeightedPenaltyModel +from .math.content_balancing.__constraint import * +from .math.content_balancing.__functions import * from .models.__adaptive_test import AdaptiveTest from .models.__algorithm_exception import AlgorithmException @@ -39,4 +42,14 @@ from .simulation.__simulation import Simulation, SimulationPool, setup_simulation_and_start -from .utils.__descriptives import bias, average_absolute_deviation, rmse \ No newline at end of file +from .utils.__descriptives import bias, average_absolute_deviation, rmse +from .utils.__funcs import load_final_test_results, load_test_results_single_participant +from .utils.__plots import ( + plot_exposure_rate, + plot_final_ability_estimates, + plot_icc, + plot_iif, + plot_exposure_rate, + plot_test_information, + plot_theta_estimation_trace +) \ No newline at end of file diff --git a/adaptivetesting/data/__csv_context.py b/adaptivetesting/data/__csv_context.py index ed8decd..89e37fe 100644 --- a/adaptivetesting/data/__csv_context.py +++ b/adaptivetesting/data/__csv_context.py @@ -3,7 +3,8 @@ import pathlib from ..models.__test_result import TestResult from ..services.__test_results_interface import ITestResults -from dataclasses import fields +import json +import ast class CSVContext(ITestResults): @@ -47,22 +48,34 @@ def save(self, test_results: List[TestResult]) -> None: file.close() def load(self) -> List[TestResult]: - """Loads test results from a CSV file for a specific participant and simulation. - Reads the CSV file located at `data/{simulation_id}/{participant_id}.csv`, - parses each row into a `TestResult` object, - and returns a list of these objects. - - Returns: - List[TestResult]: A list of `TestResult` objects loaded from the CSV file. + """Loads results from the database. + The implementation of this method is required + by the interface. However, it does not have + any implemented functionality and will throw an error + if used. + + Returns: List[TestResult] """ foldername = f"data/{self.simulation_id}" - fieldnames = list(fields(TestResult)) test_results: list[TestResult] = [] with open(f"{foldername}/{self.participant_id}.csv", "r", encoding="utf-8") as file: - reader = csv.DictReader(file, fieldnames=fieldnames) + reader = csv.DictReader(file) + next(reader, None) # skip header row for row in reader: test_result = TestResult.from_dict(row) + # showed_item is read as a string representation of a Python + # literal (e.g. a dict). Use ast.literal_eval to safely parse + # it back into a dict. Fallback to a JSON-style conversion + # if literal_eval fails. + try: + test_result.showed_item = ast.literal_eval(str(test_result.showed_item)) + except Exception: + json_string = str(test_result.showed_item).replace("'", '"').replace("None", "null") + try: + test_result.showed_item = json.loads(json_string) + except Exception: + test_result.showed_item = {} test_results.append(test_result) file.close() return test_results diff --git a/adaptivetesting/data/__read_prev_items_exp_cont.py b/adaptivetesting/data/__read_prev_items_exp_cont.py new file mode 100644 index 0000000..7f7a8a7 --- /dev/null +++ b/adaptivetesting/data/__read_prev_items_exp_cont.py @@ -0,0 +1,56 @@ +from typing import Literal +from warnings import deprecated +from ..models.__test_item import TestItem +from ..models.__test_result import TestResult +from .__csv_context import CSVContext +from .__pickle_context import PickleContext + + +def read_prev_items(format: Literal["CSV", "PICKLE"], + test_id: str, + participant_ids: list[str]) -> list[TestItem]: + """Read previously administered items. + This function is internally used to perform exposure control. + + Args: + format (Literal["CSV", "PICKLE"]): The format of the results: CSV or PICKLE. + test_id (str): The test ID / simulation ID. + participant_ids (list[str]): The participant IDs. + + Returns: + list[TestItem]: A list of TestItem objects. + """ + all_shown_test_items = [] + + for part_id in participant_ids: + test_results = read_single_participant(test_id, part_id, format) + items = [TestItem.from_dict(res.showed_item) for res in test_results] + + all_shown_test_items += items + + return all_shown_test_items + + +@deprecated("This function will be removed in future releases.") +def read_single_participant(test_id: str, participant_id: str, format: Literal["CSV", "PICKLE"]) -> list[TestResult]: + """ + Reads the test results of a particular participant. + Args: + test_id (str): The test ID / simulation ID. + participant_id (str): The participant ID. + format (Literal["CSV", "PICKLE"]): The format of the results: CSV or PICKLE. + + Returns: + list[TestResult]: A list of TestResult objects. + + Raises: + ValueError: If the format is not supported. + """ + context: CSVContext | PickleContext + if format == "CSV": + context = CSVContext(test_id, participant_id) + return context.load() + if format == "PICKLE": + context = PickleContext(test_id, participant_id) + return context.load() + raise ValueError(f"Unknown format: {format}") diff --git a/adaptivetesting/implementations/__pre_test.py b/adaptivetesting/implementations/__pre_test.py index b7ae15c..bccd12d 100644 --- a/adaptivetesting/implementations/__pre_test.py +++ b/adaptivetesting/implementations/__pre_test.py @@ -1,4 +1,4 @@ -from typing import List +from typing import List, cast import numpy as np from ..models.__test_item import TestItem import random @@ -10,6 +10,7 @@ def __init__(self, items: List[TestItem], seed: int | None = None): The pretest class can be used to draw items randomly from difficulty quantiles of the item pool. + This pretest can only be used with dichotomous IRT models and items. Args: items: Item pool @@ -18,15 +19,21 @@ def __init__(self, items: List[TestItem], seed: int | None = None): If not, the item selection will be drawn randomly, and you will not be able to reproduce the results. + Raises: + ValueError: Raised if the items are specified for polytomous IRT models. + """ self.items = items self.seed = seed + if any([isinstance(item.b, list) for item in items]): + raise ValueError("The pretest can only be used with dichotomous IRT models and items.") + def calculate_quantiles(self) -> np.ndarray: """Calculates quantiles 0.25, 0.5, 0.75 """ # get difficulties - difficulties: List[float] = [item.b for item in self.items] + difficulties: List[float] = [cast(float, item.b) for item in self.items] quantiles = np.array([]) # calculate quantiles @@ -50,7 +57,7 @@ def select_item_in_interval(self, lower: float, upper: float) -> TestItem: """ # select only items with difficulty in interval items_in_interval: List[TestItem] = [item for item in list(self.items) - if lower < item.b <= upper] + if lower < cast(float, item.b) <= upper] # draw one item randomly if self.seed is not None: random.seed(self.seed) diff --git a/adaptivetesting/implementations/__test_assembler.py b/adaptivetesting/implementations/__test_assembler.py index d9bc5a1..a335192 100644 --- a/adaptivetesting/implementations/__test_assembler.py +++ b/adaptivetesting/implementations/__test_assembler.py @@ -1,86 +1,109 @@ +from ..models.__item_selection_exception import ItemSelectionException +from ..math.content_balancing.__constraint import Constraint from ..models.__adaptive_test import AdaptiveTest from ..models.__test_item import TestItem from ..services.__estimator_interface import IEstimator -from typing import Any, Type +from typing import Any, Type, TypedDict, Callable, Literal from ..math.item_selection.__maximum_information_criterion import maximum_information_criterion from ..models.__algorithm_exception import AlgorithmException from ..implementations.__pre_test import PreTest from ..models.__test_result import TestResult +from ..models.__misc import ResultOutputFormat from ..services.__item_selection_protocol import ItemSelectionStrategy +from ..math.content_balancing.__content_balancing import CONTENT_BALANCING +from ..math.content_balancing.__weighted_penalty_model import WeightedPenaltyModel +from ..math.content_balancing.__maximum_priority_index import MaximumPriorityIndex +from ..math.estimators.__prior import Prior +from ..math.exposure_control.__exposure_control import EXPOSURE_CONTROL +from ..math.exposure_control.__randomesque import Randomesque +from ..math.exposure_control.__mpi_exposure_control import MaximumPriorityIndexExposureControl +import inspect + + +class EstimatorArgs(TypedDict): + prior: Prior | None + optimization_interval: tuple[float, float] + model: Literal["GRM", "GPCM"] | None + + +class ContentBalancingArgs(TypedDict): + constraints: list[Constraint] | None + """constraints that are applied to the item selection""" + constraint_weight: float | Callable[[AdaptiveTest], float] | None + """weight of the constraints + This can also be a function taking adaptive test as an input argument. + This allows the user to specify custom weight values depending + on the specific states and progress of the test.""" + information_weight: float | Callable[[AdaptiveTest], float] | None + """weight of the item information + This can also be a function taking adaptive test as an input argument. + This allows the user to specify custom weight values depending + on the specific states and progress of the test.""" + + +class ExposureControlArgs(TypedDict): + constraints: list[Constraint] | None + """Constraints applied for Maximum Priority Index exposure control.""" + participant_ids: list[str] | None + """Participant ids to read the previously administered test in order to + perform exposure control (MPI only). + """ + output_format: ResultOutputFormat | None + """Format in which the previous tests have been saved (MPI only).""" + n_items: int | None + """number of items to select for Randomesque items selection""" + seed: int | None + """random seed for the final item selection during Randomesque item selection""" class TestAssembler(AdaptiveTest): """ TestAssembler is a subclass of AdaptiveTest designed to assemble and administer adaptive tests, optionally including a pretest phase. It supports customizable ability estimation and item selection strategies. - Args: - - item_pool: The pool of test items available for selection. - - simulation_id: Identifier for the simulation run. - - participant_id: Identifier for the participant. - - ability_estimator (Type[IEstimator]): The estimator class used for ability estimation. - - estimator_args (dict[str, Any], optional): - Arguments for the ability estimator. Defaults to {"prior": None, "optimization_interval": (-10, 10)}. - - item_selector (ItemSelectionStrategy, optional): - Function or strategy for selecting the next item. Defaults to maximum_information_criterion. - - item_selector_args (dict[str, Any], optional): Arguments for the item selector. Defaults to {}. - - pretest (bool, optional): Whether to run a pretest phase before the main test. Defaults to False. - - pretest_seed (int | None, optional): Random seed for pretest item selection. Defaults to None. - - true_ability_level (optional): The true ability level of the participant (for simulation). - - initial_ability_level (optional): The initial ability estimate. Defaults to 0. - - simulation (bool, optional): Whether the test is run in simulation mode. Defaults to True. - - debug (bool, optional): Whether to enable debug output. Defaults to False. - - **kwargs: Additional keyword arguments passed to the AdaptiveTest superclass. - + Methods: estimate_ability_level(): Estimates the current ability level using the specified estimator and handles exceptions for specific response patterns (all correct or all incorrect). - + get_next_item() -> TestItem: Selects the next item to administer using the specified item selection strategy. - + run_test_once(): Runs a single iteration of the test, including an optional pretest phase. Handles item administration, response collection, ability estimation, and result recording. - + Attributes: __ability_estimator: The estimator class for ability estimation. - + __estimator_args: Arguments for the ability estimator. - + __item_selector: The item selection strategy. - + __item_selector_args: Arguments for the item selector. - + __pretest: Whether to run a pretest phase. - + __pretest_seed: Random seed for pretest item selection. """ + def __init__(self, item_pool, simulation_id, participant_id, ability_estimator: Type[IEstimator], - estimator_args: dict[str, Any] = { + estimator_args: EstimatorArgs = { "prior": None, - "optimization_interval": (-10, 10) + "optimization_interval": (-10, 10), + "model": None }, item_selector: ItemSelectionStrategy = maximum_information_criterion, # type: ignore item_selector_args: dict[str, Any] = {}, + model_type: Literal["GRM", "GPCM"] | None = None, + content_balancing: None | CONTENT_BALANCING = None, + content_balancing_args: ContentBalancingArgs | None = None, + exposure_control: None | EXPOSURE_CONTROL = None, + exposure_control_args: None | ExposureControlArgs = None, pretest: bool = False, pretest_seed: int | None = None, true_ability_level=None, @@ -88,13 +111,63 @@ def __init__(self, simulation=True, debug=False, **kwargs): + """ + Args: + + item_pool: The pool of test items available for selection. + + simulation_id: Identifier for the simulation run. + + participant_id: Identifier for the participant. + + ability_estimator (Type[IEstimator]): The estimator class used for ability estimation. + + estimator_args (EstimatorArgs, optional): + Arguments for the ability estimator. Defaults to {"prior": None, "optimization_interval": (-10, 10)}. + + item_selector (ItemSelectionStrategy, optional): + Function or strategy for selecting the next item. Defaults to maximum_information_criterion. + + item_selector_args (dict[str, Any], optional): Arguments for the item selector. Defaults to {}. + + content_balancing (CONTENT_BALANCING, optional): Selected content balancing strategy. Defaults to None. + If a content balancing strategy is specified, the item selection strategy will be ignored. + + content_balancing_args (ContentBalancingArgs, optional): Arguments for the content balancing strategy. + Defaults to None. + + exposure_control (EXPOSURE_CONTROL, optional): Exposure control strategy. Defaults to None. + If an exposure control strategy is specified, the item selection strategy will be ignored. + + exposure_control_args (ExposureControlArgs, optional): Arguments for the exposure control strategy. + Defaults to None. + + pretest (bool, optional): Whether to run a pretest phase before the main test. Defaults to False. + + pretest_seed (int | None, optional): Random seed for pretest item selection. Defaults to None. + + true_ability_level (optional): The true ability level of the participant (for simulation). + + initial_ability_level (optional): The initial ability estimate. Defaults to 0. + + simulation (bool, optional): Whether the test is run in simulation mode. Defaults to True. + + debug (bool, optional): Whether to enable debug output. Defaults to False. + + **kwargs: Additional keyword arguments passed to the AdaptiveTest superclass. + """ self.__ability_estimator = ability_estimator self.__estimator_args = estimator_args self.__item_selector = item_selector self.__item_selector_args = item_selector_args + self.content_balancing = content_balancing + self.content_balancing_args = content_balancing_args + self.exposure_control = exposure_control + self.exposure_control_args = exposure_control_args self.__pretest = pretest self.__pretest_seed = pretest_seed - + self.__estimator_args["model"] = model_type + super().__init__(item_pool, simulation_id, participant_id, @@ -103,7 +176,7 @@ def __init__(self, simulation, debug, **kwargs) - + def estimate_ability_level(self): """ Estimates the ability level of a test-taker based on their response pattern and answered items. @@ -113,17 +186,23 @@ def estimate_ability_level(self): it assigns a default estimation value (-10 for all incorrect, 10 for all correct) and recalculates the standard error. Otherwise, it raises an AlgorithmException with additional context. - + Returns: tuple[float, float]: A tuple containing the estimated ability level (float) and its standard error (float). - + Raises: AlgorithmException: If estimation fails for reasons other than all responses being identical. """ + # filter estimator args + sig = inspect.signature(self.__ability_estimator) + allowed = set(sig.parameters.keys()) + filtered_estimator_args = {k: v for k, v in self.__estimator_args.items() if k in allowed} + + # setup estimator estimator = self.__ability_estimator( self.response_pattern, self.answered_items, - **self.__estimator_args + **filtered_estimator_args # type: ignore ) try: @@ -143,10 +222,14 @@ def estimate_ability_level(self): when wrong when running {type(estimator)}""") from exception return estimation, standard_error - + def get_next_item(self) -> TestItem: """ Selects and returns the next test item based on the current ability level and item selector strategy. + If a content balancing strategy is specified, the item selection strategy will be ignored. + Instead, the item selected by the content balancing strategy will be returned. + This also applies to exposure control. + However, content balancing and exposure control cannot be specified at the same time Returns: TestItem: The next item to be administered in the test, as determined by the item selector. @@ -154,12 +237,106 @@ def get_next_item(self) -> TestItem: Raises: Any exceptions raised by the item selector function. """ - item = self.__item_selector( - self.item_pool.test_items, - self.ability_level, - **self.__item_selector_args - ) - return item + item: TestItem | None + if self.content_balancing is None and self.exposure_control_args is None: + # content balancing an exposure control are not specified + # filter item selection args + sig = inspect.signature(self.__item_selector) + allowed = set(sig.parameters.keys()) + filtered_item_selector_args = {k: v for k, v in self.__item_selector_args.items() if k in allowed} + + item = self.__item_selector( + self.item_pool.test_items, + self.ability_level, + **filtered_item_selector_args + ) + return item + elif self.content_balancing and self.exposure_control: + raise ValueError("Content balancing and exposure cannot be specified at the same time!") + # content balancing only + elif self.content_balancing and self.exposure_control is None: + if self.content_balancing_args is not None: + # which strategy has been selected + if self.content_balancing == "WeightedPenaltyModel": + # parse content balancing args + + # setup wep + adaptive_test = self + wep = WeightedPenaltyModel( + adaptive_test, + constraints=self.check_args_are_not_none( + "constraints", + self.content_balancing_args["constraints"]), + constraint_weight=self.check_args_are_not_none( + "constraint_weights", + self.content_balancing_args["constraint_weight"]), + information_weight=self.check_args_are_not_none( + "information_weight", + self.content_balancing_args["information_weight"])) + + item = wep.select_item() + if item is None: + raise ItemSelectionException( + f"""Something went wrong when selecting an item using {self.content_balancing}""") + else: + return item + elif self.content_balancing == "MaximumPriorityIndex": + adaptive_test = self + mpi = MaximumPriorityIndex( + adaptive_test, + constraints=self.check_args_are_not_none( + "constraints", + self.content_balancing_args["constraints"])) + + item = mpi.select_item() + + if item is None: + raise ItemSelectionException( + f"""Something went wrong when selecting an item using {self.content_balancing}""") + else: + return item + else: + raise ValueError("content_balancing_args cannot be None when using content balancing.") + # exposure control only + elif self.content_balancing is None and self.exposure_control: + if self.exposure_control_args is None: + raise ValueError("exposure_control_args cannot be None when using exposure control.") + # which strategy has been selected + if self.exposure_control == "Randomesque": + # Randomesque + adaptive_test = self + dict_keys = list(self.exposure_control_args.keys()) + if "seed" not in dict_keys or "n_items" not in dict_keys: + raise ValueError("exposure_control_args are not correctly specified") + + if self.exposure_control_args["n_items"] is not None: + randomesque = Randomesque( + adaptive_test=adaptive_test, + n_items=self.exposure_control_args["n_items"], + seed=self.exposure_control_args["seed"] + ) + return randomesque.select_item() + else: + raise ValueError("n_items cannot be None.") + + if self.exposure_control == "MaximumPriorityIndex": + if (self.exposure_control_args["participant_ids"] + is None or self.exposure_control_args["output_format"] is None): + raise ValueError("exposure_control_args are not correctly specified") + mpi = MaximumPriorityIndexExposureControl( + self, + constraints=self.exposure_control_args["constraints"], + participant_ids=self.exposure_control_args["participant_ids"], + format=self.exposure_control_args["output_format"] + ) + + selected_item = mpi.select_item() + if selected_item is None: + raise ItemSelectionException("Fatal! Not appropriated item was " + "selected using MPI for exposure control") + else: + return selected_item + raise ValueError(f"Something went wrong when selecting an item using {self.content_balancing}.") def run_test_once(self): """ @@ -172,12 +349,12 @@ def run_test_once(self): - Removes the item from the item pool. - Estimates the ability level and standard error after pretest responses. - Records test results for each pretest item, with the final item including the first ability estimation. - + Returns: The result of the superclass's run_test_once() method. """ # check if to run pretest - if self.__pretest is True: + if self.__pretest: pretest = PreTest( self.item_pool.test_items, self.__pretest_seed @@ -185,7 +362,7 @@ def run_test_once(self): # get selected items random_items = pretest.select_random_item_quantile() for item in random_items: - if self.simulation is True: + if self.simulation: response = self.item_pool.get_item_response(item) else: # not simulation @@ -229,3 +406,22 @@ def run_test_once(self): self.test_results.append(intermediate_result) return super().run_test_once() + + def check_args_are_not_none(self, key: str, x: Any | None) -> Any: + """This functions checks if an object is none. + If not a ValueError is raised. + + Args: + key (str): parameter name where the object is typically assigned + x (Any | None): object + + Raises: + ValueError: raised if the object is None. + + Returns: + Any: object + """ + if x is not None: + return x + else: + raise ValueError(f"{key} cannot be None.") diff --git a/adaptivetesting/math/__gen_response_pattern.py b/adaptivetesting/math/__gen_response_pattern.py index 7731194..37355a6 100644 --- a/adaptivetesting/math/__gen_response_pattern.py +++ b/adaptivetesting/math/__gen_response_pattern.py @@ -1,17 +1,24 @@ from .estimators.__functions.__estimators import probability_y1 +from .estimators.__functions.__poly.__gpcm import GPCM +from .estimators.__functions.__poly.__grm import GRM from ..models.__test_item import TestItem import numpy as np +from typing import Literal, cast +from scipy.stats import multinomial +from scipy.special import softmax def generate_response_pattern(ability: float, items: list[TestItem], + model: Literal["GRM", "GPCM"] | None = None, seed: int | None = None) -> list[int]: """Generates a response pattern for a given ability level - and item difficulties. Also, a seed can be set. + and item difficulties. A seed may be set for reproducibility. Args: ability (float): participants ability items (list[TestItem]): test items + model (Literal["GRM", "GPCM"], optional): model type (required for polytomous models) seed (int, optional): Seed for the random process. Returns: @@ -23,6 +30,37 @@ def generate_response_pattern(ability: float, else: rng = np.random.RandomState() + if all([item.is_polytomous() for item in items]): + if model is None: + raise ValueError("model has to be specified for polytomous items") + else: + return gen_pattern_poly( + ability, + items, + model, + rng + ) + else: + return gen_pattern_dichotomous(ability, + items, + rng) + + +def gen_pattern_dichotomous(ability: float, + items: list[TestItem], + rng: np.random.RandomState) -> list[int]: + """ + Generates a response pattern for a given ability level for an IRT + model with dichotomous test items (e.g., 4PL, 3PL). + + Args: + ability (float): participants ability + items (list[TestItem]): test items + rng (np.random.RandomState): random state (numpy object) + + Returns: + list[int]: generated response pattern + """ responses: list[int] = [] for item in items: @@ -31,20 +69,73 @@ def generate_response_pattern(ability: float, b=np.array(item.b), c=np.array(item.c), d=np.array(item.d)) - + # Handle numpy scalar/array return properly if hasattr(probability_of_success, 'item'): prob_scalar = probability_of_success.item() else: prob_scalar = float(probability_of_success) - + # Validate probability bounds if not (0 <= prob_scalar <= 1): raise ValueError(f"Invalid probability: {prob_scalar}. Must be between 0 and 1.") - + # simulate response based on probability of success random_val = rng.random_sample() response = 1 if random_val < prob_scalar else 0 responses.append(response) return responses + + +def gen_pattern_poly( + ability: float, + items: list[TestItem], + model: Literal["GRM", "GPCM"], + rng: np.random.RandomState +) -> list[int]: + """ + Generates a response pattern for a given ability level for polytomous items. + + Args: + ability (float): participants ability + items (list[TestItem]): test items + model (literal, optional): model type (GRM, or GPCM) + rng (np.random.RandomState, optional): random state (numpy object) + + Returns: + list[int]: response pattern + """ + responses: list[int] = [] + # loop through all items + for item in items: + # calculate probability for every class + log_probabilities: list[float] = [] + if model == "GRM": + for t_i in range(len(cast(list, item.b)) + 1): + log_prob = GRM.category_prob(ability, + item.a, + cast(list, item.b), + response_pattern=t_i) + log_probabilities.append(log_prob) + elif model == "GPCM": + for t_i in range(len(cast(list, item.b)) + 1): + log_prob = GPCM.category_prob(ability, + item.a, + cast(list, item.b), + response_pattern=t_i) + log_probabilities.append(log_prob) + + # draw from multinomial distribution for final response + # the probability for a response in k categories is 1 + probabilities = softmax(np.array(log_probabilities)) + mn_draw = cast(np.ndarray, multinomial.rvs( + n=1, + p=probabilities, + size=(), + random_state=rng + )).astype(int) + response = np.argmax(mn_draw).item() + responses.append(response) + + return responses diff --git a/adaptivetesting/math/content_balancing/__constraint.py b/adaptivetesting/math/content_balancing/__constraint.py new file mode 100644 index 0000000..98a86b1 --- /dev/null +++ b/adaptivetesting/math/content_balancing/__constraint.py @@ -0,0 +1,23 @@ +from dataclasses import dataclass + + +@dataclass +class Constraint: + """Constraint for Exposure Control and Content Balancing + """ + name: str + """Constraint name. This string has to be the same + in the associated items. + """ + weight: float + """Weight of this constraint. + """ + prevalence: float + """Frequency / Relative Frequency of a constraint and its items. + For MPI, this value has to be an integer > 0. + For WEP, this may be a float between 0 and 1. + """ + lower: float | None = None + """Lower bound of the constraint. Only required for WEP.""" + upper: float | None = None + """Upper bound of the constraint. Only required for WEP.""" diff --git a/adaptivetesting/math/content_balancing/__content_balancing.py b/adaptivetesting/math/content_balancing/__content_balancing.py new file mode 100644 index 0000000..59e1aaa --- /dev/null +++ b/adaptivetesting/math/content_balancing/__content_balancing.py @@ -0,0 +1,35 @@ +from abc import ABC, abstractmethod +from ...models.__test_item import TestItem +from ...models.__adaptive_test import AdaptiveTest +from .__constraint import Constraint +from typing import Literal + + +type CONTENT_BALANCING = Literal["WeightedPenaltyModel", "MaximumPriorityIndex"] +"""Default available content balancing methods.""" + + +class ContentBalancing(ABC): + """Abstract base class for content balancing methods. + + Abstract Methods + ------------------ + - `select_item` + """ + def __init__(self, adaptive_test: AdaptiveTest, + constraints: list[Constraint]): + """ + Args: + adaptive_test (AdaptiveTest): instance of the adaptive test + constraints (list[Constraint]): constraints that are applied to the item selection + """ + pass + + @abstractmethod + def select_item(self) -> TestItem | None: + """Select an item based on the implemented selection rules + + Returns: + TestItem | None: selected test item + """ + pass diff --git a/adaptivetesting/math/content_balancing/__functions.py b/adaptivetesting/math/content_balancing/__functions.py new file mode 100644 index 0000000..cd83fdf --- /dev/null +++ b/adaptivetesting/math/content_balancing/__functions.py @@ -0,0 +1,266 @@ +from .__constraint import Constraint +from ...models.__test_item import TestItem +from ...models.__item_selection_exception import ItemSelectionException +from ...math.estimators.__test_information import item_information_function +from typing import Literal + + +def compute_priority_index(item: TestItem, + group_weights: dict[str, float], + required_items: dict[str, float], + shown_items: dict[str, float], + current_ability: float, + model: Literal['GRM', 'GPCM'] | None = None) -> float: + """Calculates the priority index of a given item. + + Args: + item (TestItem): Item for which to calculate the priority index + group_weights (dict[str, float]): Dictionary with the group names and their weights + Example: `{"math": 1, "english": 1}`. These weight show how important a specific + constraint is for the item selection process + required_items (int): number of items required to be shown per constraint + shown_items (int): number of items already shown per constraint + current_ability (float): currently estimated ability level + model (Literal['GRM', 'GPCM'] | None): model type. Required for polytomous items. + + Returns: + float: priority index of an item + + Raises: + ItemSelectionException: Raised if the additional properties of the items are not correctly formatted. + """ + try: + item_groups: list[str] = item.additional_properties["category"] + + if not isinstance(item_groups, list): + raise ItemSelectionException("Additional properties of the items are not correctly formatted.") + except KeyError: + raise ItemSelectionException("Additional properties of the items are not correctly formatted.") + priority_index: float = 1.0 + + for group in item_groups: + priority_index = priority_index * group_weights[group] \ + * compute_quota_left(required_items=required_items[group], shown_items=shown_items[group]) + + # weight fisher information + priority_index = priority_index * float(item_information_function( + ability=current_ability, + item=item, + model=model + )) + + return priority_index + + +def compute_quota_left(required_items: int | float, + shown_items: int | float) -> float: + """ + Calculates the quota left (items left allowed to be shown) for a given constraint/group. + + Args: + required_items (int | float): number of required items per constraint + shown_items (int | float): number of already shown items per constraint + + Returns: + float: calculated quota for the given constraint. Results in a float between 0 and 1. + + Example: + `compute_quota_left(10, 8)` + """ + quota = (required_items - shown_items) / required_items + return quota + + +def compute_prop(n_administered: int, + prevalence: float, + n_remaining: int, + test_length: int) -> float: + """Calculates the expected proportion + of items with a specific constraint + + Args: + n_administered (int): number of constraint items administered + prevalence (float): proportion of items in the pool with given constraint + n_remaining (int): remaining items in pool with constraint + test_length (int): length of the test + + Returns: + float: expected proportion + """ + if test_length != 0: + expected_proportion = (n_administered + prevalence * n_remaining) / test_length + return expected_proportion + else: + return 0.0 + + +def compute_expected_difference(proportion: float, + constraint_target: float) -> float: + """Calculates expected difference between + expected proportion and the constraint target + + Args: + proportion (float): expected proportion + constraint_target (float): constraint target + + Returns: + float: expected difference + """ + expected_difference = proportion - constraint_target + return expected_difference + + +def compute_penalty_value(prop: float, + lower: float, + upper: float) -> float: + """Calculates the penalty value for an item + + Args: + prop (float): expected proportion + lower (float): lower bound for proportion of items + upper (float): upper bound for proportion of items + + Returns: + float: penalty value + """ + penalty_value: float = float("NaN") + mid: float = (upper + lower) / 2 + + if prop < lower: + d = lower - mid + k = 2 + penalty_value = ((1 / (k * d)) * (compute_expected_difference( + proportion=prop, + constraint_target=mid) ** 2) + (d / k)) + + if prop >= upper: + a = upper - mid + k = 2 + penalty_value = ((1 / (k * a)) * (compute_expected_difference( + proportion=prop, + constraint_target=mid) ** 2) + (a / k)) + + if upper > prop >= lower: + penalty_value = compute_expected_difference(proportion=prop, + constraint_target=mid) + + return penalty_value + + +def compute_total_content_penalty_value_for_item(item: TestItem, + shown_items: list[TestItem], + available_items: list[TestItem], + constraints: list[Constraint]) -> float: + """Calculates the total content penalty value for a given item + + Args: + item (TestItem): given test item + shown_items: shown item + available_items: available items in the test + constraints (list[Constraint]): constraints assigned to the test and its items + + Returns: + float: total content penalty value + """ + assigned_item_constraints: list[str] = item.additional_properties["category"] + assigned_constraints = [constraint for constraint in constraints if constraint.name in assigned_item_constraints] + + total_penalty_value = 0.0 + for constraint in assigned_constraints: + # type checks + if constraint.lower is None: + raise ValueError("lower cannot be None here.") + if constraint.upper is None: + raise ValueError("upper cannot be None here.") + # find number of administered items within constraint + n_administered = len([ + item for item in shown_items if constraint.name in item.additional_properties["category"] + ]) + n_remaining = len(available_items) + test_length = len(shown_items) + + # calculation + proportion = compute_prop( + n_administered=n_administered, + prevalence=constraint.prevalence, + n_remaining=n_remaining, + test_length=test_length + ) + + total_penalty_value = total_penalty_value + compute_penalty_value( + prop=proportion, + lower=constraint.lower, + upper=constraint.upper + ) * constraint.weight + + return total_penalty_value + + +def standardize_total_content_constraint_penalty_value(item_penalty_value: float, + minimum: float, + maximum: float) -> float: + """Standardize total content constraint penalty values. + + Args: + item_penalty_value (float): unstandardized item penalty value + minimum (float): minimum of the item penalty values over all eligible items + maximum (float): maximum of the item penalty values over all eligible items + + Returns: + float: standardized total content constraint penalty value + """ + try: + standardized_value = (item_penalty_value - minimum) / (maximum - minimum) + return standardized_value + except ZeroDivisionError: + return 0 + + +def standardize_item_information(item_information: float, + maximum: float) -> float: + """Standardize the item information + + Args: + item_information (float): information of an item + maximum (float): maximum information value across all eligible items + + Returns: + float: standardized item information + """ + standardized_item_information_value = item_information / maximum + return standardized_item_information_value + + +def compute_information_penalty_value(standardized_item_information: float) -> float: + """Compute information penalty value with respect to the information + + Args: + standardized_item_information (float): standardized item information + + Returns: + float: information penalty + """ + information_penalty = -(standardized_item_information ** 2) + return information_penalty + + +def compute_weighted_penalty_value(constraint_weight: float, + standardized_constraint_penalty_value: float, + information_weight: float, + information_penalty_value: float) -> float: + """Calculates the weighted penalty value. + The `constraint_weight` and `information_weight` parameters can be used + to balance the content constraint and item information. + + Args: + constraint_weight (float): constraint weight + standardized_constraint_penalty_value (float): standardized constraint penalty value + information_weight (float): information weight + information_penalty_value (float): information penalty value + + Returns: + float: weighted penalty value + """ + weighted_penalty = constraint_weight * standardized_constraint_penalty_value \ + + information_weight * information_penalty_value + return weighted_penalty diff --git a/adaptivetesting/math/content_balancing/__init__.py b/adaptivetesting/math/content_balancing/__init__.py new file mode 100644 index 0000000..d55c95f --- /dev/null +++ b/adaptivetesting/math/content_balancing/__init__.py @@ -0,0 +1 @@ +from .__functions import * \ No newline at end of file diff --git a/adaptivetesting/math/content_balancing/__maximum_priority_index.py b/adaptivetesting/math/content_balancing/__maximum_priority_index.py new file mode 100644 index 0000000..099eeca --- /dev/null +++ b/adaptivetesting/math/content_balancing/__maximum_priority_index.py @@ -0,0 +1,82 @@ +from .__content_balancing import ContentBalancing +from ...models.__test_item import TestItem +from ...models.__adaptive_test import AdaptiveTest +from .__constraint import Constraint +from .__functions import compute_priority_index +import numpy as np + + +class MaximumPriorityIndex(ContentBalancing): + """This content balancing method follows Cheng & Chang (2009). + A weight it applied to the item information considering the + current state of constraint fulfillment. + + References + ----------- + Cheng, Y., & Chang, H. (2009). The maximum priority index method for severely constrained item selection + in computerized adaptive testing. + British Journal of Mathematical and Statistical Psychology, 62(2), 369–383. + https://doi.org/10.1348/000711008X304376 + + """ + def __init__(self, adaptive_test: AdaptiveTest, constraints: list[Constraint]): + """This content balancing method follows Cheng & Chang (2009). + A weight it applied to the item information considering the + current state of constraint fulfillment. + + Args: + adaptive_test (AdaptiveTest): instance of the adaptive test + constraints (list[Constraint]): constraints that are applied to the item selection + """ + super().__init__(adaptive_test, constraints) + self.adaptive_test = adaptive_test + self.constraints = constraints + + def select_item(self) -> TestItem | None: + """Select the next item to administer based on the maximum priority index method. + Returns: + TestItem: The selected test item. + """ + # compute priority index for every item + available_items = self.adaptive_test.item_pool.test_items + shown_items = self.adaptive_test.answered_items + priority_indices: list[float] = [] + + for item in available_items: + # get associated constraints + associated_constraints = [ + constraint + for constraint in self.constraints + if constraint.name in item.additional_properties["category"] + ] + + group_weights: dict[str, float] = {} + required_items: dict[str, float] = {} + shown_items_per_constraint: dict[str, float] = {} + + for constraint in associated_constraints: + group_weights[constraint.name] = constraint.weight + required_items[constraint.name] = constraint.prevalence + n_shown_items = len([ + shown_item + for shown_item in shown_items + if constraint.name in shown_item.additional_properties["category"] + ]) + shown_items_per_constraint[constraint.name] = float(n_shown_items) + + # calculate priority index + pix = compute_priority_index( + item=item, + group_weights=group_weights, + required_items=required_items, + shown_items=shown_items_per_constraint, + current_ability=self.adaptive_test.ability_level + ) + + priority_indices.append(pix) + + # select the item with the highest priority index + max_p_i = np.argmax(priority_indices) + selected_item = available_items[max_p_i] + + return selected_item diff --git a/adaptivetesting/math/content_balancing/__weighted_penalty_model.py b/adaptivetesting/math/content_balancing/__weighted_penalty_model.py new file mode 100644 index 0000000..2b0502a --- /dev/null +++ b/adaptivetesting/math/content_balancing/__weighted_penalty_model.py @@ -0,0 +1,337 @@ +from typing import Literal, Callable +from ..estimators.__test_information import item_information_function +from ...models.__test_item import TestItem +from .__functions import ( + compute_prop, + compute_total_content_penalty_value_for_item, + standardize_total_content_constraint_penalty_value, + standardize_item_information, + compute_information_penalty_value, + compute_weighted_penalty_value +) +from .__constraint import Constraint +from .__content_balancing import ContentBalancing +from ...models.__adaptive_test import AdaptiveTest + + +CONSTRAINT_GROUP = Literal["A", "B", "C"] +ITEM_GROUP = Literal["green", "orange", "yellow", "red", None] + + +class WeightedPenaltyModel(ContentBalancing): + """This content balancing method follows Shin et al. (2009) + and allows to apply constraints to the item selection. + The users can define a custom weight for the item information and the constraint. + + References + ------------ + Shin, C. D., Chien, Y., Way, W. D., & Swanson, L. (2009). Weighted Penalty Model for Content Balancing in CATS. + Pearson. + https://www.pearsonassessments.com/content/dam/school/global/clinical/us/assets/testnav/weighted-penalty-model.pdf + + """ + def __init__(self, + adaptive_test: AdaptiveTest, + constraints: list[Constraint], + constraint_weight: float | Callable[[AdaptiveTest], float], + information_weight: float | Callable[[AdaptiveTest], float] + ): + """ + This content balancing method follows Shin et al. (2009) + and allows to apply constraints to the item selection. + The users can define a custom weight for the item information and the constriant. + + Args: + adaptive_test (AdaptiveTest): instance of the adaptive test + constraints (list[Constraint]): constraints that are applied to the item selection + constraint_weight (float | Callable[[AdaptiveTest], float]): weight of the constraints + This can also be a function taking adaptive test as an input argument. + This allows the user to specify custom weight values depending + on the specific states and progress of the test. + information_weight (float | Callable[[AdaptiveTest], float]): weight of the item information + This can also be a function taking adaptive test as an input argument. + This allows the user to specify custom weight values depending + on the specific states and progress of the test. + """ + super().__init__(adaptive_test, constraints) + self.items = adaptive_test.item_pool.test_items + self.ability = adaptive_test.ability_level + self.shown_items = adaptive_test.answered_items + self.constraints = constraints + + # setup + self.eligible_items: list[tuple[TestItem, float, ITEM_GROUP]] = [] + + # only used internally + if callable(constraint_weight): + self.constraint_weight = constraint_weight(adaptive_test) + else: + self.constraint_weight = constraint_weight + + if callable(information_weight): + self.information_weight = information_weight(adaptive_test) + else: + self.information_weight = information_weight + + def select_item(self) -> TestItem | None: + """Select the next item to administer based on the weighted penalty model. + + Returns: + TestItem | None: The selected TestItem or None if no eligible items are available. + """ + self.prepare_item_pool() + if len(self.eligible_items) > 0: + return self.eligible_items[0][0] + else: + return None + + def prepare_item_pool(self): + """Prepares item pool for the item selection + and calls are functions required to perform the necessary calculations""" + # calculate item information for every item + item_information_list = self.calculate_information() + + max_item = max(item_information_list) + + content_penalties = self.calculate_content_penalties() + + max_content_penalty = max(content_penalties) + min_content_penalty = min(content_penalties) + + self.calculate_weighted_penalty_for_all_items( + item_information_list=item_information_list, + max_item=max_item, + content_penalties=content_penalties, + max_content_penalty=max_content_penalty, + min_content_penalty=min_content_penalty + ) + + group_assignment: list[tuple[Constraint, CONSTRAINT_GROUP]] = self.get_constraint_group_assignments() + + # form a list of candidate items + self.form_list_of_candidate_items(group_assignment) + + # order items + self.order_candidate_items() + + def calculate_information(self, + model: Literal['GRM', 'GPCM'] | None = None) -> list[float]: + """ + Calculates the item information for every item + Args: + model: model type. Required for polytomous models. + + Returns: + list of item information + """ + information_list = [ + float(item_information_function( + ability=self.ability, + item=item, + model=model + )) + for item in self.items + ] + return information_list + + def calculate_content_penalties(self) -> list[float]: + """Calculate content penalty values for every item""" + content_penalties = [ + compute_total_content_penalty_value_for_item( + item=item, + shown_items=self.shown_items, + available_items=self.items, + constraints=self.constraints + ) + for item in self.items + ] + return content_penalties + + def calculate_weighted_penalty_for_all_items(self, + item_information_list: list[float], + max_item: float, + content_penalties: list[float], + max_content_penalty: float, + min_content_penalty: float): + """Calculate the weighted penalty value for every item""" + for i, item in enumerate(self.items): + weighted_penalty_value = self.calculate_weighted_penalty_value( + item_information=item_information_list[i], + max_information=max_item, + constraint_weight=self.constraint_weight, + information_weight=self.information_weight, + content_penalty=content_penalties[i], + maximum_total_content_penalty=max_content_penalty, + minimum_total_content_penalty=min_content_penalty, + ) + + self.eligible_items.append((item, weighted_penalty_value, None)) + + def get_constraint_group_assignments(self) -> list[tuple[Constraint, CONSTRAINT_GROUP]]: + """Assign every constraint to a constraint group depending on the number + of items shown from each specific constraint.""" + group_assignment: list[tuple[Constraint, CONSTRAINT_GROUP]] = [] + for constraint in self.constraints: + # calculate proportion of the constraint + n_administered: int = len( + [item for item in self.shown_items if constraint.name in item.additional_properties["category"]] + ) + n_remaining: int = len( + [item for item in self.items if constraint.name in item.additional_properties["category"]] + ) + test_length: int = len(self.shown_items) + prop = compute_prop( + n_administered=n_administered, + n_remaining=n_remaining, + prevalence=constraint.prevalence, + test_length=test_length, + ) + # assign color group per proportion + group_assignment.append(self.assign_color_group_per_proportion( + constraint, prop + )) + + return group_assignment + + @staticmethod + def assign_color_group_per_proportion(constraint: Constraint, + prop: float): + """ + Implements constraint assignment logic. + Args: + constraint (Constraint): constraint + prop (float): proportion + + Returns: + tuple[Constraint, str]: constraint and assigned group + """ + if constraint.lower is not None and constraint.upper is not None: + if prop <= constraint.lower: + return (constraint, "A") + if constraint.lower <= prop <= constraint.upper: + return (constraint, "B") + if constraint.upper <= prop: + return (constraint, "C") + else: + raise ValueError("constraint.lower and constraint.upper may not be None.") + + def form_list_of_candidate_items(self, + group_assignment: list[tuple[Constraint, CONSTRAINT_GROUP]]) -> None: + """ + Form a list of candidate items according to the constraint group assignment. + Args: + group_assignment (list[tuple[Constraint, CONSTRAINT_GROUP]): list of constraints and assigned groups + + """ + for i, item_entry in enumerate(self.eligible_items): + item, weighted_penalty_value, _ = item_entry + # find associated constraint + associated_constraints = [constraint_assignment + for constraint_assignment in group_assignment + if constraint_assignment[0].name in item.additional_properties["category"] + ] + self.eligible_items[i] = self.assign_items_to_item_group( + item, + associated_constraints, + weighted_penalty_value + ) + + @staticmethod + def assign_items_to_item_group( + item: TestItem, + associated_constraints: list[tuple[Constraint, Literal['A', 'B', 'C']]], + weighted_penalty_value: float + ): + """ + Assign items according to the constraint group assignment to an item group (color group) + Args: + item (TestItem): item + associated_constraints (list[tuple[Constraint, Literal['A', 'B', 'C']]]): + constraints relevant for this item + weighted_penalty_value (float): calculated weighted penalty value of this item + + Returns: + tuple[TestItem, float, str]: item, weighted penalty value and assigned color + """ + group_set = set([group for _, group in associated_constraints]) + + # if all associated constraints A or B -> green group + if group_set.issubset({"A", "B"}) and "A" in group_set: + return (item, weighted_penalty_value, "green") + # if all A, B, C, or A, C -> orange + elif group_set == {"A", "C"} or group_set == {"A", "B", "C"}: + return (item, weighted_penalty_value, "orange") + # if all B -> yellow + elif group_set == {"B"}: + return (item, weighted_penalty_value, "yellow") + # if all B, C -> red + elif group_set == {"B", "C"} or group_set == {"C"}: + return (item, weighted_penalty_value, "red") + else: + return (item, weighted_penalty_value, None) + + def order_candidate_items(self): + """Order candidate items according to the color group assignment. + """ + # between group ordering: green, orange, yellow, red + # within group ordering: ascending order of weighted penalty value + self.eligible_items = sorted( + self.eligible_items, + key=lambda x: ( + {"green": 0, "orange": 1, "yellow": 2, "red": 3, None: 4}[x[2]], + x[1] + ) + ) + + @staticmethod + def calculate_weighted_penalty_value(content_penalty: float, + minimum_total_content_penalty: float, + maximum_total_content_penalty: float, + item_information: float, + max_information: float, + constraint_weight: float, + information_weight: float + ) -> float: + """ + Calculate the weighted penalty value of an item. + Args: + content_penalty: content penalty value + minimum_total_content_penalty: minimum total content penalty value + maximum_total_content_penalty: maximum total content penalty value + item_information: item information + max_information: maximum item information + constraint_weight: constraint weight + information_weight: information weight + + Returns: + weighted penalty value + """ + # reference content penalty + total_content_penalty_value = content_penalty + + # standardize total content constraint penalty value + standardized_total_content_penalty_value = standardize_total_content_constraint_penalty_value( + item_penalty_value=total_content_penalty_value, + minimum=minimum_total_content_penalty, + maximum=maximum_total_content_penalty + ) + + # calculate standardized item information + standardized_item_information = standardize_item_information( + item_information=item_information, + maximum=max_information + ) + + # calculate information penalty value + information_penalty_value = compute_information_penalty_value( + standardized_item_information=standardized_item_information + ) + + # compute weighted penality value + weighted_penalty_value = compute_weighted_penalty_value( + constraint_weight=constraint_weight, + standardized_constraint_penalty_value=standardized_total_content_penalty_value, + information_weight=information_weight, + information_penalty_value=information_penalty_value, + ) + return weighted_penalty_value diff --git a/adaptivetesting/math/estimators/__bayes_modal_estimation.py b/adaptivetesting/math/estimators/__bayes_modal_estimation.py index 344346d..2fd7313 100644 --- a/adaptivetesting/math/estimators/__bayes_modal_estimation.py +++ b/adaptivetesting/math/estimators/__bayes_modal_estimation.py @@ -1,19 +1,21 @@ -from typing import List, Tuple +from typing import List, Tuple, Literal, cast import numpy as np from ...services.__estimator_interface import IEstimator from ...models.__test_item import TestItem -from ...models.__algorithm_exception import AlgorithmException -from .__functions.__bayes import maximize_posterior, likelihood -from .__prior import Prior, NormalPrior, CustomPrior, CustomPriorException -from .__test_information import test_information_function +from .__functions.__bayes import maximize_posterior +from .__prior import Prior +from .__test_information import test_information_function, poly_test_information_function +from .__functions.__poly.__gpcm import GPCM +from .__functions.__poly.__grm import GRM class BayesModal(IEstimator): def __init__(self, response_pattern: List[int] | np.ndarray, - items: List[TestItem], + items: list[TestItem], prior: Prior, - optimization_interval: Tuple[float, float] = (-10, 10)): + optimization_interval: Tuple[float, float] = (-10, 10), + model: Literal["GRM", "GPCM"] | None = None,): """This class can be used to estimate the current ability level of a respondent given the response pattern and the corresponding item difficulties. @@ -24,80 +26,66 @@ def __init__(self, Args: response_pattern (List[int] | np.ndarray ): list of response patterns (0: wrong, 1:right) - items (List[TestItem]): list of answered items + items (list[TestItem]): list of answered items prior (Prior): prior distribution optimization_interval (Tuple[float, float]): interval used for the optimization function + + model (Literal["GRM", "GPCM"], optional): model type (required for polytomous models) """ super().__init__(response_pattern, items, optimization_interval) self.prior = prior + # decide type of model used + if all([isinstance(item.b, list) for item in items]): + self.type: Literal["poly", "dich"] = "poly" + self.model = model + else: + self.type = "dich" + def get_estimation(self) -> float: """Estimate the current ability level using Bayes Modal. - If a `NormalPrior` is used, the `bounded` optimizer is used + The `bounded` optimizer is used to get the ability estimate. - For any other prior, it cannot be guaranteed that the optimizer will converge correctly. - Therefore, the full posterior distribution is calculated - and the maximum posterior value is selected. - - Because this function uses a switch internally to determine - whether a optimizer is used for the estimate or not, - you have to create your custom priors from the correct base class (`CustomPrior`). - Otherwise, the estimate may not necessarily be correct! - + Raises: AlgorithmException: Raised when maximum could not be found. - CustomPriorException: Raised when custom prior is not based on the `CustomPrior` class. Returns: float: ability estimation """ - if type(self.prior) is NormalPrior: - # get estimate using a classical optimizers approach - return maximize_posterior( - self.a, - self.b, - self.c, - self.d, - self.response_pattern, - self.prior, - self.optimization_interval - ) - # else, we have to calculate the full posterior distribution - # because the optimizers do not correctly identify the maximum of the function - else: - # check that the used prior is really inherited from - # the CustomPrior base class - if not isinstance(self.prior, CustomPrior): - raise CustomPriorException("It seems like you are using a non-normal prior but", - "did not use the CustomPrior base class!") - - mu = np.linspace(self.optimization_interval[0], - self.optimization_interval[1], - num=1000) - # calculate likelihood values for every mu - try: - lik_values = np.array([ - likelihood( - i, - self.a, - self.b, - self.c, - self.d, - self.response_pattern - ) - for i in mu - ]) - - # add prior - unmarginalized_posterior = lik_values * np.log(self.prior.pdf(mu)) - # find argmin and return mu - estimate_index = np.argmin(unmarginalized_posterior) - return float(mu[estimate_index].astype(float)) - except Exception as e: - raise AlgorithmException(e) + if self.type == "dich": + return maximize_posterior(self.a, + self.b, + self.c, + self.d, + self.response_pattern, + self.prior, + optimization_interval=self.optimization_interval) + + if self.type == "poly": + if self.model == "GRM": + grm = GRM() + return grm.maximize_posterior( + self.a_params, + self.thresholds_list, + cast(list[int], self.response_pattern.tolist()), + self.prior, + self.optimization_interval + ) + + if self.model == "GPCM": + gpcm = GPCM() + return gpcm.maximize_posterior( + self.a_params, + self.thresholds_list, + cast(list[int], self.response_pattern.tolist()), + self.prior, + self.optimization_interval + ) + raise ValueError("model and/or type have not been correctly specified") def get_standard_error(self, estimation: float) -> float: """Calculates the standard error for the given estimated ability level. @@ -108,15 +96,29 @@ def get_standard_error(self, estimation: float) -> float: Returns: float: standard error of the ability estimation """ - test_information = test_information_function( - np.array(estimation, dtype=float), - a=self.a, - b=self.b, - c=self.c, - d=self.d, - prior=self.prior, - optimization_interval=self.optimization_interval - ) + if self.type == "dich": + test_information = test_information_function( + np.array(estimation, dtype=float), + a=self.a, + b=self.b, + c=self.c, + d=self.d, + prior=self.prior, + optimization_interval=self.optimization_interval + ) + + else: + if self.model is None: + raise ValueError("model cannot be None") + else: + test_information = poly_test_information_function( + mu=estimation, + a_params=self.a_params, + thresholds_list=self.thresholds_list, + model_type=self.model, + optimization_interval=self.optimization_interval, + prior=self.prior + ) sd_error = 1 / np.sqrt(test_information) return float(sd_error) diff --git a/adaptivetesting/math/estimators/__expect_a_posteriori.py b/adaptivetesting/math/estimators/__expect_a_posteriori.py index b31f51a..f07612f 100644 --- a/adaptivetesting/math/estimators/__expect_a_posteriori.py +++ b/adaptivetesting/math/estimators/__expect_a_posteriori.py @@ -2,9 +2,12 @@ from scipy.integrate import trapezoid from .__bayes_modal_estimation import BayesModal from ...models.__test_item import TestItem -from .__functions.__bayes import likelihood +from .__functions.__estimators import log_likelihood from .__prior import Prior from math import pow +from typing import Literal, cast +from .__functions.__poly.__gpcm import GPCM +from .__functions.__poly.__grm import GRM class ExpectedAPosteriori(BayesModal): @@ -12,7 +15,8 @@ def __init__(self, response_pattern: list[int] | np.ndarray, items: list[TestItem], prior: Prior, - optimization_interval: tuple[float, float] = (-10, 10)): + optimization_interval: tuple[float, float] = (-10, 10), + model: Literal["GRM", "GPCM"] | None = None,): """This class can be used to estimate the current ability level of a respondent given the response pattern and the corresponding item difficulties. @@ -22,37 +26,85 @@ def __init__(self, Args: response_pattern (List[int] | np.ndarray): list of response patterns (0: wrong, 1:right) - items (List[TestItem]): list of answered items + items (list[TestItem]): list of answered items prior (Prior): prior distribution optimization_interval (Tuple[float, float]): interval used for the optimization function + + model (Literal["GRM", "GPCM"], optional): model type (required for polytomous models) """ super().__init__(response_pattern, items, prior, optimization_interval) + # decide type of model used + if all([isinstance(item.b, list) for item in items]): + self.type: Literal["poly", "dich"] = "poly" + self.model = model + else: + self.type = "dich" + def get_estimation(self) -> float: """Estimate the current ability level using EAP. Returns: float: ability estimation """ - x = np.linspace(self.optimization_interval[0], self.optimization_interval[1], 1000) + if self.type == "dich": + return self.get_estimation_4pl() - prior_pdf = self.prior.pdf(x) + if self.type == "poly": + if self.model == "GRM": + grm = GRM() + return grm.posterior_mean( + self.a_params, + self.thresholds_list, + cast(list[int], self.response_pattern.tolist()), + self.prior, + self.optimization_interval + ) + + if self.model == "GPCM": + gpcm = GPCM() + return gpcm.posterior_mean( + self.a_params, + self.thresholds_list, + cast(list[int], self.response_pattern.tolist()), + self.prior, + self.optimization_interval + ) + raise ValueError("model and/or type have not been correctly specified") - likelihood_vals = np.vectorize(lambda mu: likelihood(mu, - self.a, - self.b, - self.c, - self.d, - self.response_pattern))(x) + def get_estimation_4pl(self) -> float: + x = np.linspace(self.optimization_interval[0], self.optimization_interval[1], 1000) - numerator = trapezoid(x * likelihood_vals * prior_pdf, x) + if hasattr(self.prior, "logpdf"): + log_prior = self.prior.logpdf(x) + else: + log_prior = np.log(self.prior.pdf(x) + 1e-300) - denominator = trapezoid(likelihood_vals * prior_pdf, x) + log_likelihood_vals = np.vectorize( + lambda mu: log_likelihood(mu, + self.a, + self.b, + self.c, + self.d, + self.response_pattern) + )(x) - estimation = numerator / denominator + log_posterior = log_likelihood_vals + log_prior + # use log-sum-exp stabilization + max_log = np.nanmax(log_posterior) + weights = np.exp(log_posterior - max_log) + + numerator = trapezoid(x * weights, x) + denominator = trapezoid(weights, x) + np.finfo(float).eps + + if denominator == 0 or not np.isfinite(denominator): + raise ValueError("Denominator (integral of posterior) is zero or " + "non-finite — check interval/prior/likelihood.") + + estimation = numerator / denominator return estimation def get_standard_error(self, estimated_ability: float) -> float: @@ -61,29 +113,53 @@ def get_standard_error(self, estimated_ability: float) -> float: The currently estimated ability level is required as parameter. Args: - estimated_ability (float): _description_ - - Raises: - NotImplementedError: Either an instance of NormalPrior or CustomPrior has to be used. - If you want to use another calculation method for the standard, - you have to specifically override this method. + estimated_ability (float): estimated ability level Returns: float: standard error of the ability estimation """ x = np.linspace(self.optimization_interval[0], self.optimization_interval[1], 1000) - prior_pdf = self.prior.pdf(x) - likelihood_vals = np.vectorize(lambda mu: likelihood(mu, - self.a, - self.b, - self.c, - self.d, - self.response_pattern))(x) + # get log-prior in a numerically stable way + if hasattr(self.prior, "logpdf"): + log_prior = self.prior.logpdf(x) + else: + log_prior = np.log(self.prior.pdf(x) + 1e-300) - numerator = trapezoid((x - estimated_ability) ** 2 * likelihood_vals * prior_pdf, x) + log_likelihood_vals: np.ndarray + + if self.type == "dich": + log_likelihood_vals = np.vectorize(lambda mu: log_likelihood(mu, + self.a, + self.b, + self.c, + self.d, + self.response_pattern))(x) + if self.type == "poly": + if self.model == "GPCM": + log_likelihood_vec = np.vectorize( + lambda mu: GPCM.log_likelihood(mu, + self.a_params, + self.thresholds_list, + cast(list[int], self.response_pattern.tolist())) + ) + log_likelihood_vals = log_likelihood_vec(x) + if self.model == "GRM": + log_likelihood_vec = np.vectorize( + lambda mu: GRM.log_likelihood(mu, + self.a_params, + self.thresholds_list, + cast(list[int], self.response_pattern.tolist())) + ) + log_likelihood_vals = log_likelihood_vec(x) + + log_posterior = log_likelihood_vals + log_prior + max_log = np.nanmax(log_posterior) + weights = np.exp(log_posterior - max_log) + + numerator = trapezoid((x - estimated_ability) ** 2 * weights, x) - denominator = trapezoid(likelihood_vals * prior_pdf, x) + denominator = trapezoid(weights, x) standard_error_result = pow(numerator / denominator, 0.5) diff --git a/adaptivetesting/math/estimators/__functions/__bayes.py b/adaptivetesting/math/estimators/__functions/__bayes.py index 24362a2..0babd56 100644 --- a/adaptivetesting/math/estimators/__functions/__bayes.py +++ b/adaptivetesting/math/estimators/__functions/__bayes.py @@ -2,6 +2,7 @@ from scipy.optimize import minimize_scalar, OptimizeResult # type: ignore from ..__prior import Prior from ....models.__algorithm_exception import AlgorithmException +from .__estimators import log_likelihood from .__estimators import probability_y0, probability_y1 @@ -14,38 +15,35 @@ def maximize_posterior( prior: Prior, optimization_interval: tuple[float, float] = (-10, 10) ) -> float: - """_summary_ + """Get the maximum of the posterior distribution Args: a (np.ndarray): item parameter a - b (np.ndarray): item parameter b - c (np.ndarray): item parameter c - d (np.ndarray): item parameter d - response_pattern (np.ndarray): response pattern (simulated or user generated) - prior (Prior): prior distribution - optimization_interval (Tuple[float, float]): interval used for the optimization function Returns: float: Bayes Modal estimator for the given parameters """ - def log_posterior(mu) -> np.ndarray: - p1 = probability_y1(mu, a, b, c, d) - p0 = probability_y0(mu, a, b, c, d) - - log_likelihood = np.sum( - (response_pattern * np.log(p1 + 1e-300)) + ( - (1 - response_pattern) * np.log(p0 + 1e-300) - )) - log_prior = np.log(prior.pdf(mu) + 1e-300) + def log_posterior(mu): + log_likelihood_res = log_likelihood(mu, a, b, c, d, response_pattern) - return log_likelihood + log_prior + if hasattr(prior, "logpdf"): + log_prior = prior.logpdf(mu) + else: + log_prior = np.log(np.clip(prior.pdf(mu), 1e-300, None)) + + log_post = log_likelihood_res + log_prior + if not np.isfinite(log_post): + return -1e300 + else: + return float(log_post.ravel()[0]) + result: OptimizeResult = minimize_scalar(lambda mu: -log_posterior(mu), bounds=optimization_interval, method="bounded") # type: ignore diff --git a/adaptivetesting/math/estimators/__functions/__estimators.py b/adaptivetesting/math/estimators/__functions/__estimators.py index 8dd1b11..21e4644 100644 --- a/adaptivetesting/math/estimators/__functions/__estimators.py +++ b/adaptivetesting/math/estimators/__functions/__estimators.py @@ -68,13 +68,9 @@ def probability_y0(mu: np.ndarray, Args: mu (np.ndarray): latent ability level - a (np.ndarray): item discrimination parameter - b (np.ndarray): item difficulty parameter - c (np.ndarray): pseudo guessing parameter - d (np.ndarray): inattention parameter Returns: @@ -96,14 +92,11 @@ def likelihood(mu: np.ndarray, Args: mu (np.ndarray): ability level - a (np.ndarray): item discrimination parameter - b (np.ndarray): item difficulty parameter - c (np.ndarray): pseudo guessing parameter - d (np.ndarray): inattention parameter + response_pattern (np.ndarray): response pattern of the answered items Returns: float: negative likelihood value of given ability value @@ -120,6 +113,33 @@ def likelihood(mu: np.ndarray, return -np.prod(terms) +def log_likelihood(mu: np.ndarray, + a: np.ndarray, + b: np.ndarray, + c: np.ndarray, + d: np.ndarray, + response_pattern: np.ndarray): + """Log-likelihood function of the 4-PL model. + For optimization purposes, the function returns the negative value of the likelihood function. + + Args: + mu (np.ndarray): ability level + a (np.ndarray): item discrimination parameter + b (np.ndarray): item difficulty parameter + c (np.ndarray): pseudo guessing parameter + d (np.ndarray): inattention parameter + response_pattern (np.ndarray): response pattern of the answered items + + Returns: + float: log-likelihood value of given ability value + """ + p1 = probability_y1(mu, a, b, c, d) + p0 = probability_y0(mu, a, b, c, d) + result = np.sum((response_pattern * np.log(p1 + 1e-300)) + ((1 - response_pattern) * np.log(p0 + 1e-300))) + + return result + + def maximize_likelihood_function(a: np.ndarray, b: np.ndarray, c: np.ndarray, @@ -131,22 +151,18 @@ def maximize_likelihood_function(a: np.ndarray, Args: a (np.ndarray): item discrimination parameter - b (np.ndarray): item difficulty parameter - c (np.ndarray): pseudo guessing parameter - d (np.ndarray): inattention parameter - response_pattern (np.ndarray): response pattern of the item border (tuple[float, float], optional): border of the optimization interval. - Defaults to (-10, 10). + Defaults to (-10, 10). Raises: AlgorithmException: if the optimization fails or the response - pattern consists of only one type of response. + pattern consists of only one type of response. AlgorithmException: if the optimization fails or the response - pattern consists of only one type of response. + pattern consists of only one type of response. Returns: float: optimized ability value @@ -155,11 +171,10 @@ def maximize_likelihood_function(a: np.ndarray, if len(set(response_pattern.tolist())) == 1: raise AlgorithmException( "Response pattern is invalid. It consists of only one type of response.") - raise AlgorithmException( - "Response pattern is invalid. It consists of only one type of response.") - result: OptimizeResult = minimize_scalar(likelihood, args=(a, b, c, d, response_pattern), - bounds=border, method='bounded') # type: ignore + result: OptimizeResult = minimize_scalar(lambda mu: -log_likelihood(mu, a, b, c, d, response_pattern), + bounds=border, + method='bounded') # type: ignore if not result.success: raise AlgorithmException(f"Optimization failed: {result.message}") diff --git a/adaptivetesting/math/estimators/__functions/__init__.py b/adaptivetesting/math/estimators/__functions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/adaptivetesting/math/estimators/__functions/__poly/__gpcm.py b/adaptivetesting/math/estimators/__functions/__poly/__gpcm.py new file mode 100644 index 0000000..0085ad6 --- /dev/null +++ b/adaptivetesting/math/estimators/__functions/__poly/__gpcm.py @@ -0,0 +1,70 @@ +import numpy as np +from scipy.special import logsumexp +import numdifftools as nd +import math +from .__poly_math import PolyModelFunctions + + +class GPCM(PolyModelFunctions): + @staticmethod + def category_prob(theta: float, + a: float, + thresholds_list: list[float], + response_pattern: int): + m = len(thresholds_list) + + # Compute eta_k values (log numerators) + etas = np.zeros(m + 1) + + for k in range(1, m + 1): + etas[k] = etas[k - 1] + a * (theta - thresholds_list[k - 1]) + + # Compute log denominator safely + log_denom = logsumexp(etas) + + # log probability + log_prob = etas[response_pattern] - log_denom + + return log_prob + + @staticmethod + def log_likelihood(theta: float, + a_params: list[float], + thresholds_list: list[list[float]], + response_pattern: list[int]): + log_lik = 0.0 + # Iterate over item indices + for item_idx in range(len(a_params)): + log_prob = GPCM.category_prob( + theta=theta, + a=a_params[item_idx], + thresholds_list=thresholds_list[item_idx], + response_pattern=response_pattern[item_idx] + ) + + log_lik += log_prob + return log_lik # Return negative log-likelihood for minimization + + @staticmethod + def fisher_information(theta: float, + a: float, + thresholds: list[float]): + """Embretson, S. E., & Reise, S. P. (2000). Item Response Theory for Psychologists. + p. 185 + primary citation Dodd, DeAyala & Koch 1995 + """ + def prob(x: float, category: int): + p = math.exp(GPCM.category_prob(x, a, thresholds, category)) + p = max(p, 1e-12) + return p + prob_d1 = nd.Derivative(prob, order=1) + + def category_information(x: float, category: int): + cat_inf = (prob_d1(x, category) ** 2) / prob(x, category) + return cat_inf + + item_inf = 0 + for cat in range(len(thresholds) + 1): + item_inf = item_inf + category_information(theta, cat) + + return item_inf diff --git a/adaptivetesting/math/estimators/__functions/__poly/__grm.py b/adaptivetesting/math/estimators/__functions/__poly/__grm.py new file mode 100644 index 0000000..c225a0b --- /dev/null +++ b/adaptivetesting/math/estimators/__functions/__poly/__grm.py @@ -0,0 +1,77 @@ +import numpy as np +import numdifftools as nd +from .__poly_math import PolyModelFunctions + + +class GRM(PolyModelFunctions): + @staticmethod + def category_prob(theta, a: float, thresholds: list[float], response_pattern: int): + k = response_pattern + # k is the category index (0, 1, ..., num_thresholds) + num_thresholds = len(thresholds) + + # Calculate P(Y >= k) + if k == 0: + p_ge_k = 1.0 + elif k > 0 and k <= num_thresholds: + p_ge_k = 1 / (1 + np.exp(-a * (theta - thresholds[k - 1]))) + else: + # Invalid category index k or k > num_categories (num_thresholds + 1) + # For likelihood calculation, return a very small positive number to avoid log(0) + # Ensure the returned type matches the expected type if theta was an array + return np.full_like(theta, 1e-10, dtype=float) if isinstance(theta, np.ndarray) else 1e-10 + + # Calculate P(Y >= k+1) + if k == num_thresholds: # k+1 would correspond to P(Y >= num_thresholds + 1) which is 0.0 + p_ge_k_plus_1 = 0.0 + elif k < num_thresholds: # k+1 is <= num_thresholds, so it uses thresholds[k] + p_ge_k_plus_1 = 1 / (1 + np.exp(-a * (theta - thresholds[k]))) + else: + # Invalid k+1 (should not be less than 0 or something) + # Ensure the returned type matches the expected type if theta was an array + return np.full_like(theta, 1e-10, dtype=float) if isinstance(theta, np.ndarray) else 1e-10 + + prob_k = p_ge_k - p_ge_k_plus_1 + return np.maximum(prob_k, 1e-10) # Use np.maximum for element-wise comparison with arrays + + @staticmethod + def log_likelihood(theta: float, + a_params: list[float], + thresholds_list: list[list[float]], + response_pattern: list[int]): + log_lik = 0.0 + # Iterate over item indices + for item_idx in range(len(a_params)): + prob = GRM.category_prob( + theta=theta, + a=a_params[item_idx], + thresholds=thresholds_list[item_idx], + response_pattern=response_pattern[item_idx] + ) + + log_lik += np.log(np.maximum(prob, 1e-12)) + return log_lik # Return negative log-likelihood for minimization + + @staticmethod + def fisher_information(theta: float, + a: float, + thresholds: list[float]): + """Embretson, S. E., & Reise, S. P. (2000). Item Response Theory for Psychologists. + p. 185 + primary citation Dodd, DeAyala & Koch 1995 + """ + def prob(x: float, category: int): + p = GRM.category_prob(x, a, thresholds, category) + p = max(p, 1e-12) + return p + prob_d1 = nd.Derivative(prob, order=1) + + def category_information(x: float, category: int): + cat_inf = (prob_d1(x, category) ** 2) / prob(x, category) + return cat_inf + + item_inf = 0 + for cat in range(len(thresholds) + 1): + item_inf = item_inf + category_information(theta, cat) + + return item_inf diff --git a/adaptivetesting/math/estimators/__functions/__poly/__init__.py b/adaptivetesting/math/estimators/__functions/__poly/__init__.py new file mode 100644 index 0000000..f0852e4 --- /dev/null +++ b/adaptivetesting/math/estimators/__functions/__poly/__init__.py @@ -0,0 +1,4 @@ +""" +This submodule holds functions used for the ability +estimation in polytomous IRT models. +""" \ No newline at end of file diff --git a/adaptivetesting/math/estimators/__functions/__poly/__poly_math.py b/adaptivetesting/math/estimators/__functions/__poly/__poly_math.py new file mode 100644 index 0000000..6fba718 --- /dev/null +++ b/adaptivetesting/math/estimators/__functions/__poly/__poly_math.py @@ -0,0 +1,193 @@ +from abc import ABC, abstractmethod +from scipy.optimize import minimize_scalar, OptimizeResult +from .....models.__algorithm_exception import AlgorithmException +from ...__prior import Prior +import numpy as np +from scipy.integrate import trapezoid + + +class PolyModelFunctions(ABC): + """ + This is an abstract base class for polytomous IRT models and + their functions used for Computerized Adaptive Testing. + + This class may be reimplemented by subclasses. + """ + @staticmethod + @abstractmethod + def category_prob(theta: float, + a: float, + thresholds_list: list[float], + response_pattern: int) -> float: + """ + Calculates the probability of a specific category. + Args: + theta (float): ability + a (float): item parameter a + thresholds_list (list[float]): list of thresholds + response_pattern (int): item response / category + + """ + pass + + @staticmethod + @abstractmethod + def log_likelihood(theta: float, + a_params: list[float], + thresholds_list: list[list[float]], + response_pattern: list[int]): + """ + Calculates the log likelihood function of the model. + + Args: + theta (float): ability + a_params (list[float]): item parameters a + thresholds_list (list[list[float]]): list of thresholds for each item + response_pattern (list[int]): response pattern + + """ + pass + + @staticmethod + @abstractmethod + def fisher_information(theta: float, + a: float, + thresholds: list[float]): + """ + Calculates the fisher information of a specific item. + + Args: + theta (float): ability + a (float): item parameter a + thresholds (list[float]): list of thresholds + """ + pass + + def maximize_likelihood_function(self, + a_params: list[float], + thresholds_list: list[list[float]], + response_pattern: list[int], + border: tuple[float, float] = (-10, 10)): + """ + Maximize the likelihood function of the model. + + Args: + a_params (list[float]): item parameters a + thresholds_list (list[list[float]]): list of thresholds for each item + response_pattern (list[int]): response pattern + border (tuple[float, float]): interval used for numerical optimization. Defaults to (-10, 10). + + Returns: + float: point (theta) where the likelihood function is maximized + """ + + result: OptimizeResult = minimize_scalar(lambda mu: -self.log_likelihood(mu, + a_params, + thresholds_list, + response_pattern), + bounds=border, + method='bounded') + + if not result.success: + raise AlgorithmException(f"Optimization failed: {result.message}") + else: + return result.x + + def maximize_posterior(self, + a_params: list[float], + thresholds_list: list[list[float]], + response_pattern: list[int], + prior: Prior, + optimization_interval: tuple[float, float] = (-10, 10) + ) -> float: + """ + Maximize the posterior function of the model. + + Args: + a_params (list[float]): item parameters a + thresholds_list (list[list[float]]): list of thresholds for each item + response_pattern (list[int]): response pattern + optimization_interval (tuple[float, float]): interval used for numerical optimization. + Defaults to (-10, 10). + prior (Prior): prior distribution used + + Returns: + float: point (theta) where the posterior function is maximized + """ + def log_posterior(mu): + log_likelihood_res = np.array(self.log_likelihood(mu, + a_params, + thresholds_list, + response_pattern)) + + if hasattr(prior, "logpdf"): + log_prior = prior.logpdf(mu) + else: + log_prior = np.log(np.clip(prior.pdf(mu), 1e-300, None)) + + log_post = log_likelihood_res + log_prior + + if not np.isfinite(log_post): + return -1e300 + else: + return float(log_post.ravel()[0]) + + result: OptimizeResult = minimize_scalar(lambda mu: -log_posterior(mu), + bounds=optimization_interval, + method="bounded") # type: ignore + + if not result.success: + raise AlgorithmException(f"Optimization failed: {result.message}") + + else: + return float(result.x) + + def posterior_mean(self, + a_params: list[float], + thresholds_list: list[list[float]], + response_pattern: list[int], + prior: Prior, + optimization_interval: tuple[float, float] = (-10, 10)) -> float: + """ + Calculate the posterior mean of the model. + + Args: + a_params (list[float]): item parameters a + thresholds_list (list[list[float]]): list of thresholds for each item + response_pattern (list[int]): response pattern + optimization_interval (tuple[float, float]): interval used for numerical optimization. + Defaults to (-10, 10). + prior (Prior): prior distribution used + + Returns: + float: posterior mean + """ + + x = np.linspace(optimization_interval[0], optimization_interval[1], 1000) + + if hasattr(prior, "logpdf"): + log_prior = prior.logpdf(x) + else: + log_prior = np.log(prior.pdf(x) + 1e-300) + + log_likelihood_vec = np.vectorize( + lambda mu: self.log_likelihood(mu, a_params, thresholds_list, response_pattern) + ) + + log_likelihood_vals = log_likelihood_vec(x) + + log_posterior = log_likelihood_vals + log_prior + + # use log-sum-exp stabilization + max_log = np.nanmax(log_posterior) + weights = np.exp(log_posterior - max_log) + + numerator = trapezoid(x * weights, x) + denominator = trapezoid(weights, x) + np.finfo(float).eps + + if denominator == 0 or not np.isfinite(denominator): + raise ValueError("Denominator (integral of posterior) is zero or " + "non-finite — check interval/prior/likelihood.") + + estimation = numerator / denominator + return estimation diff --git a/adaptivetesting/math/estimators/__init__.py b/adaptivetesting/math/estimators/__init__.py index 1193efe..4555085 100644 --- a/adaptivetesting/math/estimators/__init__.py +++ b/adaptivetesting/math/estimators/__init__.py @@ -1,7 +1,7 @@ from .__ml_estimation import MLEstimator from .__bayes_modal_estimation import BayesModal from .__expect_a_posteriori import ExpectedAPosteriori -from .__prior import Prior, NormalPrior, CustomPrior, CustomPriorException +from .__prior import Prior, NormalPrior, CustomPrior, CustomPriorException, EmpiricalPrior, SkewNormalPrior from .__functions.__estimators import probability_y0, probability_y1, maximize_likelihood_function, likelihood from .__functions.__bayes import maximize_posterior from .__test_information import test_information_function, item_information_function, prior_information_function diff --git a/adaptivetesting/math/estimators/__ml_estimation.py b/adaptivetesting/math/estimators/__ml_estimation.py index fd60343..48aea73 100644 --- a/adaptivetesting/math/estimators/__ml_estimation.py +++ b/adaptivetesting/math/estimators/__ml_estimation.py @@ -1,16 +1,20 @@ -from typing import List, Tuple +from typing import List, Tuple, Literal, cast import numpy as np from ...models.__test_item import TestItem from ...services.__estimator_interface import IEstimator from .__functions.__estimators import maximize_likelihood_function -from .__test_information import test_information_function +from .__test_information import test_information_function, poly_test_information_function +from .__functions.__poly.__gpcm import GPCM +from .__functions.__poly.__grm import GRM class MLEstimator(IEstimator): def __init__(self, response_pattern: List[int] | np.ndarray, - items: List[TestItem], - optimization_interval: Tuple[float, float] = (-10, 10), **kwargs): + items: list[TestItem], + model: Literal["GRM", "GPCM"] | None = None, + optimization_interval: Tuple[float, float] = (-10, 10), + **kwargs): """This class can be used to estimate the current ability level of a respondent given the response pattern and the corresponding item parameters. @@ -19,10 +23,21 @@ def __init__(self, Args: response_pattern (List[int]): list of response patterns (0: wrong, 1:right) - items (List[TestItem]): list of answered items + items (Sequence[BaseItem]): list of answered items + + model (Literal["GRM", "GPCM"], optional): model type (required for polytomous models) + + optimization_interval (Tuple[float, float]): tuple of (min, max) intervals used for numerical optimization. """ IEstimator.__init__(self, response_pattern, items, optimization_interval) + # decide type of model used + if all([item.is_polytomous() for item in items]): + self.type: Literal["poly", "dich"] = "poly" + self.model = model + else: + self.type = "dich" + # ignore additional kwargs del kwargs @@ -34,14 +49,33 @@ def get_estimation(self) -> float: Returns: float: ability estimation """ - - return maximize_likelihood_function(a=self.a, - b=self.b, - c=self.c, - d=self.d, - response_pattern=self.response_pattern, - border=self.optimization_interval) - + if self.type == "dich": + return maximize_likelihood_function(a=self.a, + b=self.b, + c=self.c, + d=self.d, + response_pattern=self.response_pattern, + border=self.optimization_interval) + if self.type == "poly": + if self.model == "GRM": + grm = GRM() + return grm.maximize_likelihood_function( + self.a_params, + self.thresholds_list, + cast(list[int], self.response_pattern.tolist()), + self.optimization_interval + ) + + if self.model == "GPCM": + gpcm = GPCM() + return gpcm.maximize_likelihood_function( + self.a_params, + self.thresholds_list, + cast(list[int], self.response_pattern.tolist()), + self.optimization_interval + ) + raise ValueError("model and/or type have not been correctly specified") + def get_standard_error(self, estimation) -> float: """Calculates the standard error for the given estimated ability level. @@ -51,15 +85,29 @@ def get_standard_error(self, estimation) -> float: Returns: float: standard error of the ability estimation """ - test_information = test_information_function( - np.array(estimation, dtype=float), - a=self.a, - b=self.b, - c=self.c, - d=self.d, - prior=None, - optimization_interval=self.optimization_interval - ) + if self.type == "dich": + test_information = test_information_function( + np.array(estimation, dtype=float), + a=self.a, + b=self.b, + c=self.c, + d=self.d, + prior=None, + optimization_interval=self.optimization_interval + ) + + else: + if self.model is None: + raise ValueError("model cannot be None") + else: + test_information = poly_test_information_function( + mu=estimation, + a_params=self.a_params, + thresholds_list=self.thresholds_list, + model_type=self.model, + optimization_interval=self.optimization_interval, + prior=None + ) sd_error = 1 / np.sqrt(test_information) return float(sd_error) diff --git a/adaptivetesting/math/estimators/__prior.py b/adaptivetesting/math/estimators/__prior.py index fb1b630..4e311b9 100644 --- a/adaptivetesting/math/estimators/__prior.py +++ b/adaptivetesting/math/estimators/__prior.py @@ -1,6 +1,6 @@ import numpy as np from abc import ABC, abstractmethod -from scipy.stats import norm, rv_continuous +from scipy.stats import norm, skewnorm, rv_continuous, gaussian_kde class Prior(ABC): @@ -24,7 +24,7 @@ def pdf(self, x: float | np.ndarray) -> np.ndarray: class NormalPrior(Prior): def __init__(self, mean: float, sd: float): - """Normal distribution as prior for Bayes Modal estimation + """Normal distribution as prior for Bayes Modal or EAP estimation Args: mean (float): mean of the distribution @@ -45,6 +45,43 @@ def pdf(self, x: float | np.ndarray) -> np.ndarray: ndarray: function value """ return norm.pdf(x, self.mean, self.sd) # type: ignore + + def logpdf(self, x: float | np.ndarray): + return norm.logpdf(x, self.mean, self.sd) + + +class SkewNormalPrior(Prior): + def __init__(self, skewness: float, loc: float, scale: float): + """Skew normal distribution as prior for Bayes Modal or EAP estimation + + Args: + loc (float): location parameter + + scale (float): scale parameter + """ + super().__init__() + self.skewness = skewness + self.loc = loc + self.scale = scale + + def pdf(self, x): + """Probability density function for a prior distribution + + Args: + x (float | np.ndarray): point at which to calculate the function value + + Returns: + ndarray: function value + """ + return skewnorm.pdf(x, + self.skewness, + loc=self.loc, + scale=self.scale) + + def logpdf(self, x: float | np.ndarray): + return skewnorm.logpdf(x, self.skewness, + loc=self.loc, + scale=self.scale) class CustomPrior(Prior): @@ -55,12 +92,12 @@ def __init__(self, scale: float = 1): """This class is for using a custom prior in the ability estimation in Bayes Modal or Expected a Posteriori. - Any continous, univariate random variable from the scipy.stats module can be used. + Any continuous, univariate random variable from the scipy.stats module can be used. However, you have to consult to the scipy documentation for the required parameters for the probability density function (pdf) of that particular random variable. Args: - random_variable (rv_continuous): Any continous, univariate random variable from the scipy.stats module. + random_variable (rv_continuous): Any continuous, univariate random variable from the scipy.stats module. *args (float): Custom parameters required to calculate the pdf of that specific random variable. @@ -84,6 +121,58 @@ def pdf(self, x: float | np.ndarray) -> np.ndarray: return np.array(result) +class EmpiricalPrior(Prior): + """ + A prior distribution constructed from empirical samples using a kernel density estimate (KDE). + This class wraps scipy.stats.gaussian_kde to provide a nonparametric prior estimated + from observed data. The KDE is built from the provided dataset at initialization and + used to evaluate the probability density (pdf) at query points. + + + Parameters + ---------- + dataset : np.ndarray + Samples used to fit the prior. For univariate data this can be a 1-D array of + shape (n_samples,). For multivariate data, provide an array of shape (d, n_samples) + (as expected by scipy.stats.gaussian_kde) or an array that can be transposed to + that shape. The dataset must contain at least one sample. + + Attributes + ---------- + kde : scipy.stats.kde.gaussian_kde + The fitted kernel density estimator built from the provided dataset. + + """ + def __init__(self, dataset: np.ndarray): + """ + Args: + dataset (np.ndarray): Samples used to fit the prior. For univariate data this can be a 1-D array of + shape (n_samples,). For multivariate data, provide an array of shape (d, n_samples) + (as expected by scipy.stats.gaussian_kde) or an array that can be transposed to + that shape. The dataset must contain at least one sample. + """ + super().__init__() + + self.kde = gaussian_kde(dataset) + + def pdf(self, x): + """Evaluate the estimated probability density at x. Accepts inputs compatible with + scipy.stats.gaussian_kde.__call__: for univariate data x can be a float, 1-D array + of points, or similarly shaped array for multivariate queries. + + Args: + x (float | np.ndarray): point at which to evaluate the pdf + + Raises: + ValueError: + If `dataset` is empty. + numpy.linalg.LinAlgError: + If the covariance estimate used by gaussian_kde is singular (this is raised by + scipy's implementation when the data are degenerate). + """ + return self.kde(x) + + class CustomPriorException(Exception): """This exception can be used is the custom prior is not correctly specified. diff --git a/adaptivetesting/math/estimators/__test_information.py b/adaptivetesting/math/estimators/__test_information.py index 1fd02ba..8e1686d 100644 --- a/adaptivetesting/math/estimators/__test_information.py +++ b/adaptivetesting/math/estimators/__test_information.py @@ -4,15 +4,73 @@ from scipy.integrate import trapezoid import numpy from scipy.differentiate import derivative +from typing import Literal, cast +from .__functions.__poly.__gpcm import GPCM +from .__functions.__poly.__grm import GRM +from ...models.__test_item import TestItem def item_information_function( + ability: float, + item: TestItem, + model: Literal["GRM", "GPCM"] | None = None +) -> float: + """ + Calculates the item information given an item and ability level. + If the item is polytomous, the model parameter has to be specified to + correctly calculated the item information. + + Args: + ability (float): ability level + item (TestItem): test item + model (literal["GRM", "GPCM"] | None): model parameter. Required for polytomous response variables. + + Returns: + float: item information + """ + if model == "GRM": + return GRM.fisher_information( + ability, + item.a, + cast(list, item.b), + ) + elif model == "GPCM": + return GPCM.fisher_information( + ability, + item.a, + cast(list, item.b) + ) + + else: # dichotomous + return dicho_item_information_function( + mu=np.array(ability), + a=np.array(item.a), + b=np.array(item.b), + c=np.array(item.c), + d=np.array(item.d) + ).astype(float).item() + + +def dicho_item_information_function( mu: np.ndarray, a: np.ndarray, b: np.ndarray, c: np.ndarray, d: np.ndarray ) -> np.ndarray: + """ + Internal function to calculate the item information for dichotomous items. + + Args: + mu (np.ndarray): ability level + a (np.ndarray): discrimination parameter + b (np.ndarray): difficulty parameter + c (np.ndarray): guessing parameter + d (np.ndarray): slipping parameter + + Returns: + np.ndarray: item information + """ p_y1 = probability_y1(mu, a, b, c, d) # Clip probabilities @@ -34,10 +92,12 @@ def prior_information_function(prior: Prior, of the specified prior Args: - prior (Prior): _description_ + prior (Prior): prior distribution + optimization_interval (tuple[float, float], optional): interval used for numerical integration. + Defaults to (-10, 10). Returns: - np.ndarray: _description_ + np.ndarray: calculated fisher information of the prior """ def log_prior(x): epsilon = 1e-12 # Small value to avoid log(0) @@ -63,7 +123,7 @@ def test_information_function( optimization_interval: tuple[float, float] = (-10, 10) ) -> float: """ - Calculates test information. + Calculates test information for dichotomous items. Therefore, the information is calculated for every item and then summed up. If a prior is specified, the fisher information of the prior @@ -75,12 +135,15 @@ def test_information_function( b (np.ndarray): difficulty parameter c (np.ndarray): guessing parameter d (np.ndarray): slipping parameter + prior (Prior | None, optional): prior distribution. Defaults to None. + optimization_interval (tuple[float, float], optional): interval used for numerical integration. + Defaults to (-10, 10). Returns: float: test information """ - # calcualte information for every item - item_information = np.vectorize(item_information_function)( + # calculate information for every item + item_information = np.vectorize(dicho_item_information_function)( mu, a, b, c, d ) @@ -89,3 +152,66 @@ def test_information_function( return float(item_information.sum() + prior_information) else: return float(item_information.sum()) + + +def poly_test_information_function( + mu: float, + a_params: list[float], + thresholds_list: list[list[float]], + prior: Prior | None, + model_type: Literal["GRM", "GPCM"], + optimization_interval: tuple[float, float] = (-10, 10), +) -> float: + """ + Calculates test information for polytomous items. + Therefore, the information is calculated for every item + and then summed up. + If a prior is specified, the fisher information of the prior + is calculated as well and added to the information sum. + + Args: + mu (float): ability level + a_params (list[float]): discrimination parameters + thresholds_list (list[list[float]]): list of thresholds + model_type (Literal["GRM", "GPCM"]): model type. Supported models: GRM, GPCM. + prior (Prior | None, optional): prior distribution. Defaults to None. + optimization_interval (tuple[float, float], optional): interval used for numerical integration. + Defaults to (-10, 10). + + Returns: + float: test information + + Raises: + ValueError: model type must be either GRM or GPCM. + """ + # calculate information for every test item + item_information = 0.0 + if model_type == "GRM": + for i, _ in enumerate(a_params): + inf_item_i = GRM.fisher_information( + mu, + a_params[i], + thresholds_list[i] + ) + item_information = item_information + inf_item_i + elif model_type == "GPCM": + for i, _ in enumerate(a_params): + inf_item_i = GPCM.fisher_information( + mu, + a_params[i], + thresholds_list[i] + ) + item_information = item_information + inf_item_i + else: + raise ValueError("model_type must be GRM or GPCM") + + test_information = item_information + # add prior information + if prior: + prior_information = prior_information_function( + prior=prior, + optimization_interval=optimization_interval + ) + test_information = test_information + float(prior_information) + + return test_information diff --git a/adaptivetesting/math/exposure_control/__exposure_control.py b/adaptivetesting/math/exposure_control/__exposure_control.py new file mode 100644 index 0000000..b8c1281 --- /dev/null +++ b/adaptivetesting/math/exposure_control/__exposure_control.py @@ -0,0 +1,32 @@ +from abc import ABC, abstractmethod +from typing import Literal +from ...models.__test_item import TestItem +from ...models.__adaptive_test import AdaptiveTest + + +type EXPOSURE_CONTROL = Literal["Randomesque", "MaximumPriorityIndex"] + + +class ExposureControl(ABC): + """ + Abstract base class for exposure control + + Abstract Methods + ------------------ + - `select_item` + """ + def __init__(self, adaptive_test: AdaptiveTest): + """ + Args: + adaptive_test (AdaptiveTest): instance of the adaptive test + """ + self.adaptive_test = adaptive_test + + @abstractmethod + def select_item(self, **kwargs) -> TestItem | None: + """Select an item based on the implemented selection rules + + Returns: + TestItem | None: selected test item + """ + pass diff --git a/adaptivetesting/math/exposure_control/__init__.py b/adaptivetesting/math/exposure_control/__init__.py new file mode 100644 index 0000000..75fe831 --- /dev/null +++ b/adaptivetesting/math/exposure_control/__init__.py @@ -0,0 +1,2 @@ +from .__exposure_control import ExposureControl +from .__randomesque import Randomesque \ No newline at end of file diff --git a/adaptivetesting/math/exposure_control/__mpi_exposure_control.py b/adaptivetesting/math/exposure_control/__mpi_exposure_control.py new file mode 100644 index 0000000..7e74389 --- /dev/null +++ b/adaptivetesting/math/exposure_control/__mpi_exposure_control.py @@ -0,0 +1,81 @@ +from ..content_balancing.__maximum_priority_index import MaximumPriorityIndex +from .__exposure_control import ExposureControl +from ...models.__test_item import TestItem +from ...models.__misc import ResultOutputFormat +from ..content_balancing.__functions import compute_priority_index +import numpy as np +from ...data.__read_prev_items_exp_cont import read_prev_items +from typing import Literal + + +class MaximumPriorityIndexExposureControl(MaximumPriorityIndex, ExposureControl): + """This is a reimplementation of the Maximum Priority Index for Exposure Control. + For further information see `MaximumPriorityIndex`. + """ + def __init__(self, adaptive_test, constraints, participant_ids: list[str], format: ResultOutputFormat): + super().__init__(adaptive_test, constraints) + self.participant_ids = participant_ids + self.format = format + + def select_item(self, **kwargs) -> TestItem | None: + """Select the next item to administer based on the maximum priority index method. + Returns: + TestItem: The selected test item. + """ + # compute priority index for every item + available_items = self.adaptive_test.item_pool.test_items + # skip selection if item pool is empty + if len(available_items) == 0: + return None + + # load items that have been shown to other users + format: Literal["CSV", "PICKLE"] + if self.format is ResultOutputFormat.CSV: + format = "CSV" + if self.format is ResultOutputFormat.PICKLE: + format = "PICKLE" + shown_items = read_prev_items( + test_id=self.adaptive_test.simulation_id, + participant_ids=self.participant_ids, + format=format + ) + priority_indices: list[float] = [] + + for item in available_items: + # get associated constraints + associated_constraints = [ + constraint + for constraint in self.constraints + if constraint.name in item.additional_properties["category"] + ] + + group_weights: dict[str, float] = {} + required_items: dict[str, float] = {} + shown_items_per_constraint: dict[str, float] = {} + + for constraint in associated_constraints: + group_weights[constraint.name] = constraint.weight + required_items[constraint.name] = constraint.prevalence + n_shown_items = len([ + shown_item + for shown_item in shown_items + if constraint.name in shown_item.additional_properties["category"] + ]) + shown_items_per_constraint[constraint.name] = float(n_shown_items) + + # calculate priority index + pix = compute_priority_index( + item=item, + group_weights=group_weights, + required_items=required_items, + shown_items=shown_items_per_constraint, + current_ability=self.adaptive_test.ability_level + ) + + priority_indices.append(pix) + + # select the item with the highest priority index + max_p_i = np.argmax(priority_indices) + selected_item = available_items[max_p_i] + + return selected_item diff --git a/adaptivetesting/math/exposure_control/__randomesque.py b/adaptivetesting/math/exposure_control/__randomesque.py new file mode 100644 index 0000000..fe21cce --- /dev/null +++ b/adaptivetesting/math/exposure_control/__randomesque.py @@ -0,0 +1,114 @@ +from typing import Callable, Any +import random +from .__exposure_control import ExposureControl +from ...models.__adaptive_test import AdaptiveTest +from ...models.__test_item import TestItem +from ..estimators.__test_information import item_information_function +from typing import Literal + + +class Randomesque(ExposureControl): + def __init__(self, + adaptive_test: AdaptiveTest, + n_items: int, + seed: int | None = None, + reverse: bool = True): + """ + Exposure Control using randomesque item selection. + Instead of the most informative item, the `n` most informative items are selected. + From this selection, the final item is drawn randomly. For this process, a seed + can be specified. + + Args: + adaptive_test (AdaptiveTest): instance of the adaptive test + n_items (int): number of items to select + seed (int | None): random seed for the final item selection + reverse (bool): If `True` the most informative items are selected. Default `True`. + + + References + ------------ + Kingsbury, G. G., & Zara, A. R. (1991). A Comparison of Procedures for Content-Sensitive + Item Selection in Computerized Adaptive Tests. Applied Measurement in Education, 4(3), 241–261. + Psychology and Behavioral Sciences Collection. https://doi.org/10.1207/s15324818ame0403_4 + + Kingsbury, G. G., & Zara, A. R. (1989). Procedures for selecting items for + computerized adaptive tests. Applied Measurement in Education, 2(4), 359–375. + + """ + super().__init__(adaptive_test) + + # extract items + self.items = adaptive_test.item_pool.test_items + self.ability_estimate = adaptive_test.ability_level + self.n_items = n_items + self.seed = seed + self.reverse = reverse + + def select_item(self, **kwargs) -> TestItem: + """Select an item based on the implemented selection rules + + Args: + **kwargs: additional arguments for item selection function. + Not used here but implemented for compatibility. + + Returns: + TestItem | None: selected test item + """ + selected_items = self.radomesque_item_selection( + self.items, + self.ability_estimate, + self.n_items, + self.reverse, + seed=self.seed + ) + return selected_items + + @staticmethod + def sort_by_information(item_entry: tuple[float, int]) -> float: + """ + Internal function for sorting items by their information value + + Args: + item_entry: tuple of information value and item index + + Returns: + information value of given item + """ + return item_entry[0] + + @staticmethod + def radomesque_item_selection(items: list[TestItem], + ability_estimate: float, + n_items: int, + reverse: bool = True, + item_rating_function: Callable = item_information_function, + seed: int | None = None, + model: Literal["GRM", "GPCM"] | None = None, + **kwargs: Any + ) -> TestItem: + item_information_list: list[tuple[float, int]] = [] + for i, item in enumerate(items): + information = float(item_rating_function( + ability=ability_estimate, + item=item, + model=model, + **kwargs + )) + + item_information_list.append((information, i)) + + # sort items in ascending order to have the first item be the one with the highest + # information value (default or expected settings) + item_information_list.sort(key=Randomesque.sort_by_information, reverse=reverse) + + # select first n items + selected_items = item_information_list[0:n_items] + # select only items + sub_item_pool = [items[item[1]] for item in selected_items] + + # randomly select items from sub item pool + if seed is not None: + random.seed(seed) + sampled_item = random.sample(sub_item_pool, k=1)[0] + return sampled_item diff --git a/adaptivetesting/math/item_selection/__maximum_information_criterion.py b/adaptivetesting/math/item_selection/__maximum_information_criterion.py index dcb2d0c..330d32d 100644 --- a/adaptivetesting/math/item_selection/__maximum_information_criterion.py +++ b/adaptivetesting/math/item_selection/__maximum_information_criterion.py @@ -2,17 +2,20 @@ from ...models.__item_selection_exception import ItemSelectionException from ..estimators.__test_information import item_information_function from ...models.__algorithm_exception import AlgorithmException -import numpy as np +from typing import Literal def maximum_information_criterion(items: list[TestItem], - ability: float) -> TestItem: + ability: float, + model: Literal["GRM", "GPCM"] | None = None) -> TestItem: """The maximum information criterion selected the next item for the respondent by finding the item that has the highest information value. Args: items (list[TestItem]): list of available items ability (float): currently estimated ability + model (Literal["GRM", "GPCM"] | None): model type. Required for polytomous models. + Defaults to dichotomous variables. Returns: TestItem: item that has the highest information value @@ -25,20 +28,12 @@ def maximum_information_criterion(items: list[TestItem], best_item = None for item in items: - # extract parameters from the current item - a = np.array([item.a]) - b = np.array([item.b]) - c = np.array([item.c]) - d = np.array([item.d]) - # calculate information for the current item try: information = float(item_information_function( - mu=np.array(ability, dtype=float), - a=a, - b=b, - c=c, - d=d + ability=ability, + item=item, + model=model, )) # if information is higher than before diff --git a/adaptivetesting/math/item_selection/__urrys_rule.py b/adaptivetesting/math/item_selection/__urrys_rule.py index 1eab960..4defb12 100644 --- a/adaptivetesting/math/item_selection/__urrys_rule.py +++ b/adaptivetesting/math/item_selection/__urrys_rule.py @@ -1,8 +1,10 @@ from ...models.__test_item import TestItem -from typing import List +from typing import List, cast from ...models.__item_selection_exception import ItemSelectionException +from warnings import deprecated +@deprecated("Use maximum information criterion instead.") def urrys_rule(items: List[TestItem], ability: float) -> TestItem: """Urry's rule selects the test item which has the minimal difference between @@ -16,18 +18,21 @@ def urrys_rule(items: List[TestItem], ability: float) -> TestItem: Returns: TestItem: selected test item """ - # create difference array from absolute value - difference: List[float] = [] - for item in items: - difference.append(abs(ability - item.b)) - - # get minimal difference - minimal_difference = min(difference) - - # find the item where minimal difference is equal to absolut - # value of difference - for item in items: - if abs(ability - item.b) == minimal_difference: - return item - - raise ItemSelectionException("No appropriate item could be selected.") + if all([isinstance(item.b, float) for item in items]): + # create difference array from absolute value + difference: List[float] = [] + for item in items: + difference.append(abs(ability - cast(float, item.b))) + + # get minimal difference + minimal_difference = min(difference) + + # find the item where minimal difference is equal to absolut + # value of difference + for item in items: + if abs(ability - cast(float, item.b)) == minimal_difference: + return item + + raise ItemSelectionException("No appropriate item could be selected.") + else: + raise ValueError("Urry's rule cannot be used with polytomous IRT model items!") diff --git a/adaptivetesting/models/__adaptive_test.py b/adaptivetesting/models/__adaptive_test.py index 19d9816..b749dc7 100644 --- a/adaptivetesting/models/__adaptive_test.py +++ b/adaptivetesting/models/__adaptive_test.py @@ -25,15 +25,10 @@ def __init__(self, item_pool: ItemPool, Args: item_pool (ItemPool): item pool used for the test - simulation_id (str): simulation id - participant_id (str): participant id - true_ability_level (float): true ability level (must always be set) - initial_ability_level (float): initially assumed ability level - simulation (bool): will the test be simulated. If it is simulated and a response pattern is not yet set in the item pool, it will be generated for the given true ability level. @@ -63,7 +58,7 @@ def __init__(self, item_pool: ItemPool, # if simulation is True # generate a response pattern if # it is not yet set in the item pool - if simulation is True: + if simulation: if self.item_pool.simulated_responses is None: if self.true_ability_level is not None: self.item_pool.simulated_responses = generate_response_pattern( @@ -72,20 +67,6 @@ def __init__(self, item_pool: ItemPool, seed=kwargs["seed"] if "seed" in kwargs.keys() else None ) - def get_item_difficulties(self) -> List[float]: - """ - Returns: - List[float]: difficulties of items in the item pool - """ - return [item.b for item in self.item_pool.test_items] - - def get_answered_items_difficulties(self) -> List[float]: - """ - Returns: - List[float]: difficulties of answered items - """ - return [item.b for item in self.answered_items] - def get_answered_items(self) -> List[TestItem]: """ Returns: @@ -93,18 +74,6 @@ def get_answered_items(self) -> List[TestItem]: """ return self.answered_items - # def get_ability_se(self) -> float: - # """ - # Calculate the current standard error - # of the ability estimation. - - # Returns: - # float: standard error of the ability estimation - - # """ - # answered_items = self.get_answered_items() - # return standard_error(answered_items, self.ability_level) - @abc.abstractmethod def get_next_item(self) -> TestItem: """Select next item. @@ -151,7 +120,7 @@ def run_test_once(self): # check if simulation is running response = None - if self.simulation is True: + if self.simulation: response = self.item_pool.get_item_response(item) else: # not simulation diff --git a/adaptivetesting/models/__item_pool.py b/adaptivetesting/models/__item_pool.py index ced5deb..79e6f47 100644 --- a/adaptivetesting/models/__item_pool.py +++ b/adaptivetesting/models/__item_pool.py @@ -1,5 +1,5 @@ from .__test_item import TestItem -from typing import List, Tuple +from typing import List, Tuple, cast from pandas import DataFrame @@ -64,7 +64,7 @@ def get_item_response(self, item: TestItem) -> int: item (TestItem): item to get the corresponding response Returns: - (int): response (either `0` or `1`) + (int): response (either `0` or `1` for dichotmous items or `k` for polytomous items) """ if self.simulated_responses is None: raise ValueError("Simulated responses not provided") @@ -90,29 +90,26 @@ def delete_item(self, item: TestItem) -> None: # STATIC LOAD METHODS @staticmethod def load_from_list( - b: List[float], + b: List[float] | list[list[float]], a: List[float] | None = None, c: List[float] | None = None, d: List[float] | None = None, simulated_responses: List[int] | None = None, - ids: List[int] | None = None) -> "ItemPool": + ids: List[int] | None = None, + content_categories: list[list[str]] | None = None) -> "ItemPool": """ Creates test items from a list of floats. Args: a (List[float]): discrimination parameter - - b (List[float]): difficulty parameter - - c (List[float]): guessing parameter - - d (List[float]): slipping parameter - + b (List[float] | list[list[float]]): For dichotomous models, this is the difficulty parameter. + For polytomous items, this is the list of threshold parameters. + c (List[float]): guessing parameter. Ignored for polytomous items. + d (List[float]): slipping parameter. Ignored for polytomous items. simulated_responses (List[int]): simulated responses - - ids (List[int]): item IDs. If the argument is set to `None` - all items are numbered in the order in which they are - passed to the function. + ids (List[int]): item IDs + content_categories (list[list[str]], optional): List of categories for each item. + This list is used for content balancing. Returns: List[TestItem]: item pool @@ -120,9 +117,9 @@ def load_from_list( """ items: List[TestItem] = [] - for difficulty in b: + for b_i in b: item = TestItem() - item.b = difficulty + item.b = b_i items.append(item) # check if a, b, c, d are the same length @@ -149,9 +146,12 @@ def load_from_list( raise ValueError("Length of ids and b has to be the same.") for i, id_ in enumerate(ids): items[i].id = id_ - else: - for i in range(len(b)): - items[i].id = i + + if content_categories is not None: + if len(content_categories) != len(b): + raise ValueError("Length of content_categories and b has to be the same.") + for i, groups in enumerate(content_categories): + items[i].additional_properties["category"] = groups item_pool = ItemPool(items) item_pool.simulated_responses = simulated_responses @@ -159,32 +159,33 @@ def load_from_list( return item_pool @staticmethod - def load_from_dict(source: dict[str, List[float]], + def load_from_dict(source: dict[str, list[float]] | dict[str, list], simulated_responses: List[int] | None = None, - ids: List[int] | None = None) -> "ItemPool": + ids: List[int] | None = None, + content_categories: list[list[str]] | None = None) -> "ItemPool": """Creates test items from a dictionary. The dictionary has to have the following keys: - a - - b - - c - - d + - b (list of float, for polytomous models list[list[float]] as threshold list) + - c (ignored for polytomous items) + - d (ignored for polytomous items) each containing a list of float. Args: - source (dict[str, List[float]]): item pool dictionary + source (dict[str, List[float] | list[float]]): item pool dictionary simulated_responses (List[int]): simulated responses - ids (List[int]): item IDs. If the argument is set to `None` - all items are numbered in the order in which they are - passed to the function. + ids (List[int], optional): item IDs. Default `None`. + content_categories (list[list[str]], optional): List of categories for each item. + This list is used for content balancing. Returns: List[TestItem]: item pool """ - a = source.get("a") - b = source.get("b") - c = source.get("c") - d = source.get("d") + a = cast(list[float], source.get("a")) + b = cast(list[list[float]] | list[float], source.get("b")) + c = cast(list[float] | None, source.get("c")) + d = cast(list[float] | None, source.get("d")) # check none if a is None: @@ -192,34 +193,49 @@ def load_from_dict(source: dict[str, List[float]], if b is None: raise ValueError("b cannot be None") - - if c is None: - raise ValueError("c cannot be None") - - if d is None: - raise ValueError("d cannot be None") - - # check if a, b, c, and d have the same length - if not (len(a) == len(b) == len(c) == len(d)): - raise ValueError("All lists in the source dictionary must have the same length") - + + if not all([isinstance(b_i, list) for b_i in b]): + # if b is not a list of thresholds check of c and d + if c is None: + raise ValueError("c cannot be None") + + if d is None: + raise ValueError("d cannot be None") + # check if a, b, c, and d have the same length + if not (len(a) == len(b) == len(c) == len(d)): + raise ValueError("a, b, c, and d must have the same length.") + else: + if not (len(a) == len(b)): + raise ValueError("a and b must have the same length.") + if ids is not None: if len(ids) != len(b): raise ValueError("Length of ids and b has to be the same.") + if content_categories is not None: + if len(content_categories) != len(b): + raise ValueError("Length of content_categories and b has to be the same.") + n_items = len(b) items: List[TestItem] = [] for i in range(n_items): item = TestItem() item.a = a[i] item.b = b[i] - item.c = c[i] - item.d = d[i] + + if c is not None: + item.c = c[i] + if d is not None: + item.d = d[i] if ids is not None: item.id = ids[i] - else: - item.id = i + + if "id" in source.keys(): + item.id = cast(int, source["id"][i]) + + if content_categories is not None: + item.additional_properties["category"] = content_categories[i] items.append(item) @@ -230,24 +246,17 @@ def load_from_dict(source: dict[str, List[float]], @staticmethod def load_from_dataframe(source: DataFrame) -> "ItemPool": """Creates item pool from a pandas DataFrame. - Required columns are: `a`, `b`, `c`, `d`. + Required columns are: `a`, `b`. + `c`, `d` are optional (ignored for polytomous items). Each column has to contain float values. - - A `id` column can be added to assign - each test item a unique identifier. - If there is no `id` column - all items are numbered in the order in which they are - passed to the function. - A `simulated_responses` (int values) column can be added to the DataFrame to provide simulated responses. - Args: - source (DataFrame): _description_ + source (DataFrame): source data frame Returns: - ItemPool: _description_ + ItemPool: parsed item pool """ # check if columns are present @@ -257,25 +266,34 @@ def load_from_dataframe(source: DataFrame) -> "ItemPool": if "b" not in source.columns: raise ValueError("Column 'b' not found.") - if "c" not in source.columns: - raise ValueError("Column 'c' not found.") - - if "d" not in source.columns: - raise ValueError("Column 'd' not found.") - # get values a: List[float] = source["a"].values.tolist() # type: ignore - b: List[float] = source["b"].values.tolist() # type: ignore - c: List[float] = source["c"].values.tolist() # type: ignore - d: List[float] = source["d"].values.tolist() # type: ignore + b: List[float] | list[list[float]] = source["b"].values.tolist() # type: ignore + + c: list[float] | None + if "c" in source.columns: + c: List[float] = source["c"].values.tolist() # type: ignore + else: + c = None + + d: list[float] | None + if "d" in source.columns: + d: List[float] = source["d"].values.tolist() # type: ignore + else: + d = None if "ids" in source.columns: ids: List[int] | None = source["ids"].values.tolist() # type: ignore else: ids = None + if "content_categories" in source.columns: + groups: list[list[str]] | None = source["content_categories"].values.tolist() + else: + groups = None + # create item pool - item_pool = ItemPool.load_from_list(a=a, b=b, c=c, d=d, ids=ids) + item_pool = ItemPool.load_from_list(a=a, b=b, c=c, d=d, ids=ids, content_categories=groups) # check if simulated responses are present if "simulated_responses" in source.columns: diff --git a/adaptivetesting/models/__item_selection_exception.py b/adaptivetesting/models/__item_selection_exception.py index 9ca309f..b989eb9 100644 --- a/adaptivetesting/models/__item_selection_exception.py +++ b/adaptivetesting/models/__item_selection_exception.py @@ -1,3 +1,4 @@ class ItemSelectionException(Exception): + """Custom exception for item selection errors in adaptive testing.""" def __init__(self, *args): super().__init__(*args) diff --git a/adaptivetesting/models/__test_item.py b/adaptivetesting/models/__test_item.py index 7203208..f0a27be 100644 --- a/adaptivetesting/models/__test_item.py +++ b/adaptivetesting/models/__test_item.py @@ -1,3 +1,6 @@ +from typing import TypedDict + + class TestItem: def __init__(self): """Representation of a test item in the item pool. @@ -6,28 +9,73 @@ def __init__(self): Properties: - id (int | None): item ID - a (float): discrimination parameter - - b (float): difficulty parameter - - c (float): guessing parameter - - d (float): slipping parameter / upper asymptote + - b (float | list[float]): difficulty parameter. For polytomous models, list of threshold parameters + - c (float): guessing parameter. Ignored for polytomous models. + - d (float): slipping parameter / upper asymptote. Ignored for polytomous models. + - additional_properties (dict): additional properties can be set if required. + This functionality is used for content balancing. + To use content balancing, set `category` key of the class instance + to a list of string which indicate the corresponding constraint classes. + Example: `item.additional_properties["category"] = ["Math"]` """ self.id: int | None = None self.a: float = 1 - self.b: float = float("nan") + self.b: float | list[float] = float("nan") self.c: float = 0 self.d: float = 1 + self.additional_properties: dict = {} - def as_dict(self, with_id: bool = False) -> dict[str, float | int | None]: - """Returns the item as a dictionary""" + def as_dict(self, with_id=True): + """Convert test item to a dictionary. - item_dict: dict[str, float | int | None] = { + Args: + with_id (bool, optional): Deprecated. This argument will be ignored. + Defaults to True. + + """ + ItemDict = TypedDict("ItemDict", { + "id": int | None, + "a": float, + "b": float | list[float], + "c": float, + "d": float, + "additional_properties": dict + }) + + item_dict: ItemDict = { + "id": self.id, "a": self.a, "b": self.b, "c": self.c, - "d": self.d + "d": self.d, + "additional_properties": self.additional_properties } - if with_id and self.id is not None: - item_dict["id"] = self.id - return item_dict + + @staticmethod + def from_dict(source: dict) -> "TestItem": + item = TestItem() + # copy known fields, preserving defaults if keys are missing + if "a" in source and source["a"] is not None: + item.a = source["a"] + if "b" in source and source["b"] is not None: + item.b = source["b"] + if "c" in source and source["c"] is not None: + item.c = source["c"] + if "d" in source and source["d"] is not None: + item.d = source["d"] + if "additional_properties" in source and source["additional_properties"] is not None: + item.additional_properties = source["additional_properties"] + if "id" in source and source["id"] is not None: + item.id = source["id"] + return item + + def is_polytomous(self) -> bool: + """Checks whether an item is polytomous or dichotomous. + + Returns: + bool: True if item is polytomous. + """ + return isinstance(self.b, list) diff --git a/adaptivetesting/services/__estimator_interface.py b/adaptivetesting/services/__estimator_interface.py index d97bee6..45d4725 100644 --- a/adaptivetesting/services/__estimator_interface.py +++ b/adaptivetesting/services/__estimator_interface.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import List, Tuple +from typing import List, Tuple, cast, Literal import numpy as np from ..models.__test_item import TestItem @@ -7,8 +7,9 @@ class IEstimator(ABC): def __init__(self, response_pattern: List[int] | np.ndarray, - items: List[TestItem], - optimization_interval: Tuple[float, float] = (-10, 10)): + items: list[TestItem], + optimization_interval: Tuple[float, float] = (-10, 10), + model: Literal["GRM", "GPCM"] | None = None): """This is the interface required for every possible estimator. Any estimator inherits from this class and implements @@ -16,8 +17,8 @@ def __init__(self, Args: response_pattern (List[int]): list of responses (0: wrong, 1:right) - - items (List[TestItem]): list of answered items + items (list[TestItem]): list of answered items + model: model type. Required for polytomous IRT models. """ if type(response_pattern) is not np.ndarray: self.response_pattern = np.array(response_pattern) @@ -25,11 +26,17 @@ def __init__(self, self.response_pattern = response_pattern self.optimization_interval = optimization_interval - # convert items to parameter arrays - self.a = np.array([i.a for i in items]) - self.b = np.array([i.b for i in items]) - self.c = np.array([i.c for i in items]) - self.d = np.array([i.d for i in items]) + # decide type of model used + if all([isinstance(item.b, list) for item in items]): + self.a_params = [i.a for i in items] + self.thresholds_list: list[list[float]] = [cast(list, i.b) for i in items] + else: + # convert items to parameter arrays + items_t = cast(list[TestItem], items) + self.a = np.array([i.a for i in items_t]) + self.b = np.array([i.b for i in items_t]) + self.c = np.array([i.c for i in items_t]) + self.d = np.array([i.d for i in items_t]) @abstractmethod def get_estimation(self) -> float: diff --git a/adaptivetesting/services/__item_selection_protocol.py b/adaptivetesting/services/__item_selection_protocol.py index c9cd042..bb9944b 100644 --- a/adaptivetesting/services/__item_selection_protocol.py +++ b/adaptivetesting/services/__item_selection_protocol.py @@ -13,9 +13,7 @@ class ItemSelectionStrategy(Protocol): Args: items (list[TestItem]): The list of available test items to select from. - ability (float): The current ability estimate of the test taker. - **kwargs: Additional keyword arguments that may be required by specific selection strategies. Returns: diff --git a/adaptivetesting/services/__test_results_interface.py b/adaptivetesting/services/__test_results_interface.py index 21745b3..af01038 100644 --- a/adaptivetesting/services/__test_results_interface.py +++ b/adaptivetesting/services/__test_results_interface.py @@ -4,14 +4,12 @@ class ITestResults(ABC): - def __init__(self, simulation_id: str, participant_id: str): """Interface for saving and reading test results. This interface may mainly be used for saving simulation results. Args: simulation_id (str): The simulation ID. Name of the results file. - participant_id (str): The participant ID. """ self.simulation_id = simulation_id diff --git a/adaptivetesting/simulation/__init__.py b/adaptivetesting/simulation/__init__.py index 0eeb141..fccb158 100644 --- a/adaptivetesting/simulation/__init__.py +++ b/adaptivetesting/simulation/__init__.py @@ -1 +1,5 @@ -from .__simulation import * +from .__simulation import ( + Simulation, + setup_simulation_and_start, + SimulationPool +) \ No newline at end of file diff --git a/adaptivetesting/simulation/__simulation.py b/adaptivetesting/simulation/__simulation.py index 22a1102..037bd55 100644 --- a/adaptivetesting/simulation/__simulation.py +++ b/adaptivetesting/simulation/__simulation.py @@ -18,7 +18,6 @@ def __init__(self, Args: test (AdaptiveTest): instance of an adaptive test implementation (see implementations module) - test_result_output (ResultOutputFormat): test results output format """ self.test = test @@ -41,7 +40,7 @@ def simulate(self, """ stop_test = False - while stop_test is False: + while not stop_test: # run test self.test.run_test_once() # check available items @@ -82,12 +81,9 @@ def setup_simulation_and_start(test: AdaptiveTest, Args: test (AdaptiveTest): The adaptive test instance to be simulated. - test_result_output (ResultOutputFormat): The format or handler for outputting test results. - criterion (StoppingCriterion | list[StoppingCriterion]): The criterion used to determine when the simulation should stop. - value (float): The value associated with the stopping criterion (e.g., maximum number of items, target standard error). """ @@ -99,7 +95,7 @@ def setup_simulation_and_start(test: AdaptiveTest, simulation.save_test_results() -class SimulationPool(): +class SimulationPool: def __init__(self, adaptive_tests: list[AdaptiveTest], test_result_output: ResultOutputFormat, @@ -110,9 +106,7 @@ def __init__(self, Args: adaptive_tests (list[AdaptiveTest]): List of adaptive test instances to be simulated. - - test_results_output (ResultOutputFormat): Format for outputting test results. - + test_result_output (ResultOutputFormat): Format for outputting test results. criterion (StoppingCriterion | list[StoppingCriterion]): Stopping criterion or list of criteria for the simulations. @@ -123,30 +117,47 @@ def __init__(self, self.criterion = criterion self.value = value - def start(self): + def start(self, parallel: bool = True): """ Starts the simulation by executing adaptive tests in parallel. Depending on the operating system, uses either multithreading (on Windows) or multiprocessing (on other platforms) to run the simulation for each adaptive test. Progress is displayed using a progress bar. + + Note that parallel processing is not supported for the use in jupyter notebooks. + For that, `parallel` has to be set to `False`. + + Args: + parallel (bool): process all simulations in parallel. Not supported in jupyter notebooks. + Default `True`. + """ - func = partial( - setup_simulation_and_start, - test_result_output=self.test_results_output, - criterion=self.criterion, - value=self.value - ) - # check for platform - # this is because multiprocessing is not as well supported on windows - # therefore, multithreading is used instead - if platform.system() == "Windows": - with ThreadPoolExecutor(max_workers=60) as executor: - futures = [executor.submit(func, test) for test in self.adaptive_tests] - for _ in tqdm(as_completed(futures), total=len(futures)): - pass + if parallel: + func = partial( + setup_simulation_and_start, + test_result_output=self.test_results_output, + criterion=self.criterion, + value=self.value + ) + # check for platform + # this is because multiprocessing is not as well-supported on windows + # therefore, multithreading is used instead + if platform.system() == "Windows": + with ThreadPoolExecutor(max_workers=60) as executor: + futures = [executor.submit(func, (test,)) for test in self.adaptive_tests] + for _ in tqdm(as_completed(futures), total=len(futures)): + pass + else: + with ProcessPoolExecutor() as executor: + futures = [executor.submit(func, (test,)) for test in self.adaptive_tests] + for _ in tqdm(as_completed(futures), total=len(futures)): + pass else: - with ProcessPoolExecutor() as executor: - futures = [executor.submit(func, test) for test in self.adaptive_tests] - for _ in tqdm(as_completed(futures), total=len(futures)): - pass + for test in tqdm(self.adaptive_tests): + setup_simulation_and_start( + test=test, + test_result_output=self.test_results_output, + criterion=self.criterion, + value=self.value + ) diff --git a/adaptivetesting/tests/example_item_pool.json b/adaptivetesting/tests/example_item_pool.json new file mode 100644 index 0000000..473aabf --- /dev/null +++ b/adaptivetesting/tests/example_item_pool.json @@ -0,0 +1,182 @@ +[ + { + "a": 1.3024, + "b": -0.6265, + "c": 0.2052, + "d": 0.8694, + "content_categories": [ + "math" + ] + }, + { + "a": 1.078, + "b": 0.1836, + "c": 0.1618, + "d": 0.9653, + "content_categories": [ + "math" + ] + }, + { + "a": 0.8758, + "b": -0.8356, + "c": 0.1957, + "d": 0.8595, + "content_categories": [ + "math" + ] + }, + { + "a": 0.5571, + "b": 1.5953, + "c": 0.1383, + "d": 0.8112, + "content_categories": [ + "math" + ] + }, + { + "a": 1.225, + "b": 0.3295, + "c": 0.1324, + "d": 0.7677, + "content_categories": [ + "math" + ] + }, + { + "a": 0.991, + "b": -0.8205, + "c": 0.1973, + "d": 0.7749, + "content_categories": [ + "math" + ] + }, + { + "a": 0.9968, + "b": 0.4874, + "c": 0.0058, + "d": 0.8291, + "content_categories": [ + "math" + ] + }, + { + "a": 1.1888, + "b": 0.7383, + "c": 0.1193, + "d": 0.8797, + "content_categories": [ + "math" + ] + }, + { + "a": 1.1642, + "b": 0.5758, + "c": 0.1831, + "d": 0.9155, + "content_categories": [ + "math" + ] + }, + { + "a": 1.1188, + "b": -0.3054, + "c": 0.1732, + "d": 0.8517, + "content_categories": [ + "math" + ] + }, + { + "a": 1.3024, + "b": -0.6265, + "c": 0.2052, + "d": 0.8694, + "content_categories": [ + "english" + ] + }, + { + "a": 1.078, + "b": 0.1836, + "c": 0.1618, + "d": 0.9653, + "content_categories": [ + "english" + ] + }, + { + "a": 0.8758, + "b": -0.8356, + "c": 0.1957, + "d": 0.8595, + "content_categories": [ + "english" + ] + }, + { + "a": 0.5571, + "b": 1.5953, + "c": 0.1383, + "d": 0.8112, + "content_categories": [ + "english" + ] + }, + { + "a": 1.225, + "b": 0.3295, + "c": 0.1324, + "d": 0.7677, + "content_categories": [ + "english" + ] + }, + { + "a": 0.991, + "b": -0.8205, + "c": 0.1973, + "d": 0.7749, + "content_categories": [ + "english" + ] + }, + { + "a": 0.9968, + "b": 0.4874, + "c": 0.0058, + "d": 0.8291, + "content_categories": [ + "english" + ] + }, + { + "a": 1.1888, + "b": 0.7383, + "c": 0.1193, + "d": 0.8797, + "content_categories": [ + "english" + ] + }, + { + "a": 1.1642, + "b": 0.5758, + "c": 0.1831, + "d": 0.9155, + "content_categories": [ + "english" + ] + }, + { + "a": 1.1188, + "b": -0.3054, + "c": 0.1732, + "d": 0.8517, + "content_categories": [ + "english" + ] + } +] \ No newline at end of file diff --git a/adaptivetesting/tests/test_adaptive_test.py b/adaptivetesting/tests/test_adaptive_test.py index c24beac..27c30bf 100644 --- a/adaptivetesting/tests/test_adaptive_test.py +++ b/adaptivetesting/tests/test_adaptive_test.py @@ -39,10 +39,6 @@ def get_next_item(self): def estimate_ability_level(self) -> tuple[float, float]: return 0, float("NaN") - def test_get_difficulties(self): - difficulties = self.get_item_difficulties() - self.assertEqual(difficulties, [0.24, 0.89, -0.6]) - def test_standard_error(self): """This should calculate a standard error without failing""" self.answered_items = [item1, item2] diff --git a/adaptivetesting/tests/test_bayes_modal.py b/adaptivetesting/tests/test_bayes_modal.py index 70d57fc..3fe14f1 100644 --- a/adaptivetesting/tests/test_bayes_modal.py +++ b/adaptivetesting/tests/test_bayes_modal.py @@ -1,9 +1,14 @@ import unittest from adaptivetesting.models import ItemPool -from adaptivetesting.math.estimators import BayesModal, NormalPrior, CustomPrior +from adaptivetesting.math.estimators import ( + BayesModal, + NormalPrior, + CustomPrior, + SkewNormalPrior, + EmpiricalPrior) import pandas as pd from scipy.stats import beta -from adaptivetesting.math.estimators import CustomPriorException +import numpy as np class TestBayesModal(unittest.TestCase): @@ -18,9 +23,7 @@ def test_estimation_4pl(self): "d": [0.87, 0.93, 1] }) item_pool = ItemPool.load_from_dataframe(items) - item_pool = ItemPool.load_from_dataframe(items) - response_pattern = [0, 1, 0] response_pattern = [0, 1, 0] estimator = BayesModal( response_pattern=response_pattern, @@ -30,7 +33,6 @@ def test_estimation_4pl(self): ) result = estimator.get_estimation() - self.assertAlmostEqual(result, -0.4741753, 4) @@ -61,29 +63,132 @@ def test_estimation_4pl(self): ) result = estimator.get_estimation() - self.assertAlmostEqual(result, 0.01, places=3) + self.assertAlmostEqual(result, 0, places=2) - def test_wrong_prior_implementation(self): - items = pd.DataFrame({"a": [1.3024, 1.078, 0.8758, 0.5571, 1.225, 0.991, 0.9968, 1.1888, 1.1642, 1.1188], - "b": [-0.6265, 0.1836, -0.8356, 1.5953, 0.3295, -0.8205, 0.4874, 0.7383, 0.5758, -0.3054], - "c": [0.2052, 0.1618, 0.1957, 0.1383, 0.1324, 0.1973, 0.0058, 0.1193, 0.1831, 0.1732], - "d": [0.8694, 0.9653, 0.8595, 0.8112, 0.7677, 0.7749, 0.8291, 0.8797, 0.9155, 0.8517]}) - item_pool = ItemPool.load_from_dataframe(items) - response_pattern = [0, 0, 1, 1, 1, 0, 0, 0, 0, 1] +class TestSkewNormalPriorIntegration(unittest.TestCase): + def setUp(self): + # simple 3-item pool used elsewhere in tests + items = pd.DataFrame({ + "a": [1.32, 1.07, 0.84], + "b": [-0.63, 0.18, -0.84], + "c": [0.17, 0.10, 0.19], + "d": [0.87, 0.93, 1.0] + }) + self.item_pool = ItemPool.load_from_dataframe(items).test_items + self.response_pattern = [0, 1, 0] + + def test_skewnormal_pdf_basic(self): + prior = SkewNormalPrior(skewness=4.0, loc=0.0, scale=1.0) + # scalar + p0 = prior.pdf(0.0) + self.assertTrue(np.isfinite(np.asarray(p0)).all()) + self.assertGreaterEqual(float(np.asarray(p0).ravel()[0]), 0.0) + # array + xs = np.array([-2.0, 0.0, 2.0]) + pa = prior.pdf(xs) + pa = np.asarray(pa) + self.assertEqual(pa.shape[-1], xs.shape[-1]) + self.assertTrue(np.all(pa >= 0.0)) + + def test_skewnormal_changes_estimate_vs_normal(self): + prior_norm = NormalPrior(0.0, 1.0) + prior_skew = SkewNormalPrior(skewness=6.0, loc=0.0, scale=1.0) + + est_norm = BayesModal( + response_pattern=self.response_pattern, + items=self.item_pool, + prior=prior_norm, + optimization_interval=(-4, 4), + ).get_estimation() + + est_skew = BayesModal( + response_pattern=self.response_pattern, + items=self.item_pool, + prior=prior_skew, + optimization_interval=(-4, 4), + ).get_estimation() + + self.assertTrue(np.isfinite(est_norm)) + self.assertTrue(np.isfinite(est_skew)) + # skew prior should typically shift the estimate compared to symmetric prior + self.assertNotAlmostEqual(est_norm, est_skew, places=6) + + +class TestEmpiricalPriorIntegration(unittest.TestCase): + def setUp(self): + rng = np.random.default_rng(0) + self.dataset = rng.normal(loc=0.0, scale=1.0, size=300) + self.prior = EmpiricalPrior(self.dataset) + items = pd.DataFrame({ + "a": [1.0, 1.2, 0.9], + "b": [0.0, 0.5, -0.5], + "c": [0.2, 0.2, 0.2], + "d": [1.0, 0.9, 0.95] + }) + self.item_pool = ItemPool.load_from_dataframe(items).test_items + self.response_pattern = [1, 0, 1] - # create custom prior - class WrongPrior(NormalPrior): - pass + def test_empirical_pdf_scalar_and_array(self): + scalar = self.prior.pdf(0.0) + self.assertTrue(np.isfinite(np.asarray(scalar)).all()) + self.assertGreaterEqual(float(np.asarray(scalar).ravel()[0]), 0.0) - prior = WrongPrior(0, 1) - + xs = np.array([-1.0, 0.0, 1.0]) + vals = np.asarray(self.prior.pdf(xs)) + # gaussian_kde returns shape (n_points,) for 1-D data + self.assertEqual(vals.shape[-1], xs.shape[-1]) + self.assertTrue(np.all(vals >= 0.0)) + + def test_empirical_prior_works_with_bayesmodal(self): estimator = BayesModal( - response_pattern=response_pattern, - items=item_pool.test_items, - prior=prior, - optimization_interval=(-10, 10) + response_pattern=self.response_pattern, + items=self.item_pool, + prior=self.prior, + optimization_interval=(-4, 4), ) + result = estimator.get_estimation() + self.assertTrue(np.isfinite(result)) - with self.assertRaises(CustomPriorException): - estimator.get_estimation() + +class TestNumericalStability(unittest.TestCase): + def setUp(self): + # moderate 4PL pool for stability checks + self.items = pd.DataFrame({ + "a": [1.3024, 1.078, 0.8758, 0.5571], + "b": [-0.6265, 0.1836, -0.8356, 1.5953], + "c": [0.2052, 0.1618, 0.1957, 0.1383], + "d": [0.8694, 0.9653, 0.8595, 0.8112] + }) + self.item_pool = ItemPool.load_from_dataframe(self.items).test_items + + def test_tight_normal_prior_keeps_estimate_near_mean(self): + # extremely tight prior around mean 2.0 should pull estimate close to 2.0 + prior = NormalPrior(mean=2.0, sd=1e-6) + responses = [1, 1, 1, 1] # all-correct + estimator = BayesModal( + response_pattern=responses, + items=self.item_pool, + prior=prior, + optimization_interval=(-10, 10), + ) + result = estimator.get_estimation() + self.assertTrue(np.isfinite(result)) + # result should be extremely close to the prior mean + self.assertAlmostEqual(result, 2.0, places=2) + + def test_extreme_response_patterns_do_not_crash(self): + # all incorrect + prior = NormalPrior(0.0, 1.0) + for responses in ([0, 0, 0, 0], [1, 1, 1, 1]): + estimator = BayesModal( + response_pattern=responses, + items=self.item_pool, + prior=prior, + optimization_interval=(-10, 10), + ) + result = estimator.get_estimation() + self.assertTrue(np.isfinite(result)) + # result lies within the provided optimization interval + self.assertGreaterEqual(result, -10) + self.assertLessEqual(result, 10) diff --git a/adaptivetesting/tests/test_content_balacing.py b/adaptivetesting/tests/test_content_balacing.py new file mode 100644 index 0000000..8b41d02 --- /dev/null +++ b/adaptivetesting/tests/test_content_balacing.py @@ -0,0 +1,131 @@ +import unittest +import adaptivetesting as adt +import pandas as pd + + +class TestMaximumPriorityIndex(unittest.TestCase): + def __init__(self, methodName="runTest"): + + items = pd.DataFrame({ + "a": [1.32, 1.07, 0.84], + "b": [-0.63, 0.18, -0.84], + "c": [0.17, 0.10, 0.19], + "d": [0.87, 0.93, 1], + "id": [1, 2, 3] + }) + + self.available_items = adt.ItemPool.load_from_dataframe(items).test_items + self.content_categories = ["Math", "English", "Math"] + + for i, _ in enumerate(self.available_items): + self.available_items[i].additional_properties = { + "category": [self.content_categories[i]] + } + + super().__init__(methodName) + + def test_basic_calculation(self): + adt.compute_priority_index( + item=self.available_items[0], + group_weights={ + "Math": 0.2, + "English": 0.8 + }, + required_items={ + "Math": 5, + "English": 10 + }, + shown_items={ + "Math": 0, + "English": 10 + }, + current_ability=0 + ) + + def test_quota_calculation(self): + result = adt.compute_quota_left(10, 5) + self.assertAlmostEqual(result, 0.5) + + def test_exception_list(self): + with self.assertRaises(adt.ItemSelectionException): + self.available_items[0].additional_properties["category"] = 0 + adt.compute_priority_index( + item=self.available_items[0], + group_weights={ + "Math": 0.2, + "English": 0.8 + }, + required_items={ + "Math": 5, + "English": 10 + }, + shown_items={ + "Math": 0, + "English": 10 + }, + current_ability=0 + ) + + def test_exception_key(self): + with self.assertRaises(adt.ItemSelectionException): + self.available_items[0].additional_properties.pop("category") + adt.compute_priority_index( + item=self.available_items[0], + group_weights={ + "Math": 0.2, + "English": 0.8 + }, + required_items={ + "Math": 5, + "English": 10 + }, + shown_items={ + "Math": 0, + "English": 10 + }, + current_ability=0 + ) + + +class TestMPIPolyModels(unittest.TestCase): + def __init__(self, methodName="runTest"): + + items = pd.DataFrame({ + "a": [1.32, 1.07, 0.84], + "b": [[0.2, 0.9], + [0.2, 0.9], + [0.2, 0.9]], + "id": [1, 2, 3] + }) + + self.available_items = adt.ItemPool.load_from_dataframe(items).test_items + self.content_categories = ["Math", "English", "Math"] + + for i, _ in enumerate(self.available_items): + self.available_items[i].additional_properties = { + "category": [self.content_categories[i]] + } + + super().__init__(methodName) + + def test_basic_calculation(self): + adt.compute_priority_index( + item=self.available_items[0], + group_weights={ + "Math": 0.2, + "English": 0.8 + }, + required_items={ + "Math": 5, + "English": 10 + }, + shown_items={ + "Math": 0, + "English": 10 + }, + current_ability=0 + ) + + def test_quota_calculation(self): + result = adt.compute_quota_left(10, 5) + self.assertAlmostEqual(result, 0.5) diff --git a/adaptivetesting/tests/test_eap.py b/adaptivetesting/tests/test_eap.py index 3f53e9d..9ee33fe 100644 --- a/adaptivetesting/tests/test_eap.py +++ b/adaptivetesting/tests/test_eap.py @@ -1,10 +1,14 @@ -from unittest import TestCase +import unittest import pandas as pd +import numpy as np from adaptivetesting.models import ItemPool -from adaptivetesting.math.estimators import ExpectedAPosteriori, NormalPrior +from adaptivetesting.math.estimators import (ExpectedAPosteriori, + NormalPrior, + SkewNormalPrior, + EmpiricalPrior) -class TestEAP(TestCase): +class TestEAP(unittest.TestCase): def test_estimation_4pl(self): items = pd.DataFrame({ "a": [1.32, 1.07, 0.84], @@ -25,3 +29,131 @@ def test_estimation_4pl(self): result = estimator.get_estimation() self.assertAlmostEqual(result, -0.4565068, 4) + + +class TestSkewNormalPriorIntegration(unittest.TestCase): + def setUp(self): + # simple 3-item pool used elsewhere in tests + items = pd.DataFrame({ + "a": [1.32, 1.07, 0.84], + "b": [-0.63, 0.18, -0.84], + "c": [0.17, 0.10, 0.19], + "d": [0.87, 0.93, 1.0] + }) + self.item_pool = ItemPool.load_from_dataframe(items).test_items + self.response_pattern = [0, 1, 0] + + def test_skewnormal_pdf_basic(self): + prior = SkewNormalPrior(skewness=4.0, loc=0.0, scale=1.0) + # scalar + p0 = prior.pdf(0.0) + self.assertTrue(np.isfinite(np.asarray(p0)).all()) + self.assertGreaterEqual(float(np.asarray(p0).ravel()[0]), 0.0) + # array + xs = np.array([-2.0, 0.0, 2.0]) + pa = prior.pdf(xs) + pa = np.asarray(pa) + self.assertEqual(pa.shape[-1], xs.shape[-1]) + self.assertTrue(np.all(pa >= 0.0)) + + def test_skewnormal_changes_estimate_vs_normal(self): + prior_norm = NormalPrior(0.0, 1.0) + prior_skew = SkewNormalPrior(skewness=6.0, loc=0.0, scale=1.0) + + est_norm = ExpectedAPosteriori( + response_pattern=self.response_pattern, + items=self.item_pool, + prior=prior_norm, + optimization_interval=(-4, 4), + ).get_estimation() + + est_skew = ExpectedAPosteriori( + response_pattern=self.response_pattern, + items=self.item_pool, + prior=prior_skew, + optimization_interval=(-4, 4), + ).get_estimation() + + self.assertTrue(np.isfinite(est_norm)) + self.assertTrue(np.isfinite(est_skew)) + # skew prior should typically shift the estimate compared to symmetric prior + self.assertNotAlmostEqual(est_norm, est_skew, places=6) + + +class TestEmpiricalPriorIntegration(unittest.TestCase): + def setUp(self): + rng = np.random.default_rng(0) + self.dataset = rng.normal(loc=0.0, scale=1.0, size=300) + self.prior = EmpiricalPrior(self.dataset) + items = pd.DataFrame({ + "a": [1.0, 1.2, 0.9], + "b": [0.0, 0.5, -0.5], + "c": [0.2, 0.2, 0.2], + "d": [1.0, 0.9, 0.95] + }) + self.item_pool = ItemPool.load_from_dataframe(items).test_items + self.response_pattern = [1, 0, 1] + + def test_empirical_pdf_scalar_and_array(self): + scalar = self.prior.pdf(0.0) + self.assertTrue(np.isfinite(np.asarray(scalar)).all()) + self.assertGreaterEqual(float(np.asarray(scalar).ravel()[0]), 0.0) + + xs = np.array([-1.0, 0.0, 1.0]) + vals = np.asarray(self.prior.pdf(xs)) + # gaussian_kde returns shape (n_points,) for 1-D data + self.assertEqual(vals.shape[-1], xs.shape[-1]) + self.assertTrue(np.all(vals >= 0.0)) + + def test_empirical_prior_works_with_ExpectedAPosteriori(self): + estimator = ExpectedAPosteriori( + response_pattern=self.response_pattern, + items=self.item_pool, + prior=self.prior, + optimization_interval=(-4, 4), + ) + result = estimator.get_estimation() + self.assertTrue(np.isfinite(result)) + + +class TestNumericalStability(unittest.TestCase): + def setUp(self): + # moderate 4PL pool for stability checks + self.items = pd.DataFrame({ + "a": [1.3024, 1.078, 0.8758, 0.5571], + "b": [-0.6265, 0.1836, -0.8356, 1.5953], + "c": [0.2052, 0.1618, 0.1957, 0.1383], + "d": [0.8694, 0.9653, 0.8595, 0.8112] + }) + self.item_pool = ItemPool.load_from_dataframe(self.items).test_items + + def test_tight_normal_prior_keeps_estimate_near_mean(self): + # extremely tight prior around mean 2.0 should pull estimate close to 2.0 + prior = NormalPrior(mean=2.0, sd=1e-6) + responses = [1, 1, 1, 1] # all-correct + estimator = ExpectedAPosteriori( + response_pattern=responses, + items=self.item_pool, + prior=prior, + optimization_interval=(-10, 10), + ) + result = estimator.get_estimation() + self.assertTrue(np.isfinite(result)) + # result should be extremely close to the prior mean + self.assertAlmostEqual(result, 2.0, delta=0.1) + + def test_extreme_response_patterns_do_not_crash(self): + # all incorrect + prior = NormalPrior(0.0, 1.0) + for responses in ([0, 0, 0, 0], [1, 1, 1, 1]): + estimator = ExpectedAPosteriori( + response_pattern=responses, + items=self.item_pool, + prior=prior, + optimization_interval=(-10, 10), + ) + result = estimator.get_estimation() + self.assertTrue(np.isfinite(result)) + # result lies within the provided optimization interval + self.assertGreaterEqual(result, -10) + self.assertLessEqual(result, 10) diff --git a/adaptivetesting/tests/test_exposure_control_mpi.py b/adaptivetesting/tests/test_exposure_control_mpi.py new file mode 100644 index 0000000..1b01290 --- /dev/null +++ b/adaptivetesting/tests/test_exposure_control_mpi.py @@ -0,0 +1,87 @@ +import unittest +from unittest.mock import patch + +from adaptivetesting.math.exposure_control.__mpi_exposure_control import ( + MaximumPriorityIndexExposureControl, +) +from adaptivetesting import ResultOutputFormat, Constraint + + +class DummyConstraint: + def __init__(self, name, weight=1.0, prevalence=0.0): + self.name = name + self.weight = weight + self.prevalence = prevalence + + +class DummyItem: + def __init__(self, identifier, categories): + # production code expects item.additional_properties["category"] + self.identifier = identifier + self.additional_properties = {"category": categories} + + +class DummyItemPool: + def __init__(self, items): + self.test_items = items + + +class DummyAdaptiveTest: + def __init__(self, items, simulation_id="sim1", ability_level=0.0): + self.item_pool = DummyItemPool(items) + self.simulation_id = simulation_id + self.ability_level = ability_level + + +class MPIExposureControlTests(unittest.TestCase): + @patch( + "adaptivetesting.math.exposure_control.__mpi_exposure_control.read_prev_items", + return_value=[], + ) + @patch( + "adaptivetesting.math.exposure_control.__mpi_exposure_control.compute_priority_index" + ) + def test_selects_item_with_highest_priority_index(self, mock_compute, _mock_read): + # arrange: three items with different categories + i1 = DummyItem("i1", ["A"]) + i2 = DummyItem("i2", ["B"]) + i3 = DummyItem("i3", ["A"]) + adaptive = DummyAdaptiveTest([i1, i2, i3]) + + constraints = [ + DummyConstraint("A", weight=1.0, prevalence=2.0), + DummyConstraint("B", weight=1.0, prevalence=1.0), + ] + + scores = {"i1": 0.2, "i2": 0.8, "i3": 0.5} + + def fake_compute(item, **kwargs): + res = scores.get(str(getattr(item, "identifier", None)), 0.0) + return res + + mock_compute.side_effect = fake_compute + + controller = MaximumPriorityIndexExposureControl( + adaptive, constraints, participant_ids=["p1"], + format=ResultOutputFormat.CSV + ) + selected = controller.select_item() + + self.assertIs(selected, i2) # item with score 0.8 should be chosen + + @patch( + "adaptivetesting.math.exposure_control.__mpi_exposure_control.read_prev_items", + return_value=[], + ) + def test_returns_none_on_empty_pool(self, _mock_read): + adaptive = DummyAdaptiveTest([]) + constraints: list[Constraint] = [] + controller = MaximumPriorityIndexExposureControl(adaptive, + constraints, + participant_ids=[], + format=ResultOutputFormat.CSV) + self.assertIsNone(controller.select_item()) + + +if __name__ == "__main__": + unittest.main() diff --git a/adaptivetesting/tests/test_full_tests.py b/adaptivetesting/tests/test_full_tests.py new file mode 100644 index 0000000..336c723 --- /dev/null +++ b/adaptivetesting/tests/test_full_tests.py @@ -0,0 +1,224 @@ +# This file is used to perform a full run of +# specific adaptiv test specifications. +import unittest +import adaptivetesting as adt +import pandas as pd +import shutil +import pathlib + + +class TestContentBalancing(unittest.TestCase): + def __init__(self, methodName="runTest"): + super().__init__(methodName) + + items = pd.DataFrame({ + "a": [1.32, 1.07, 0.84], + "b": [-0.63, 0.18, -0.84], + "c": [0.17, 0.10, 0.19], + "d": [0.87, 0.93, 1], + "id": [1, 2, 3] + }) + + self.available_items = adt.ItemPool.load_from_dataframe(items).test_items + self.content_categories = ["Math", "English", "Math"] + + for i, _ in enumerate(self.available_items): + self.available_items[i].additional_properties = { + "category": [self.content_categories[i]] + } + + def test_maximum_priority_index(self): + item_pool = adt.ItemPool(self.available_items, + [0, 1, 0]) + + adaptive_test = adt.TestAssembler( + item_pool=item_pool, + simulation_id="1", + participant_id="12", + ability_estimator=adt.MLEstimator, + content_balancing="MaximumPriorityIndex", + content_balancing_args={ # type: ignore + "constraints": [ + adt.Constraint( + "Math", + 0.5, + 0.2 + ), + adt.Constraint( + "English", + 0.5, + 0.1 + ) + ] + } + ) + + sim = adt.Simulation(adaptive_test, adt.ResultOutputFormat.CSV) + sim.simulate() + + def test_weighted_penalty_model(self): + item_pool = adt.ItemPool(self.available_items, + [0, 1, 0]) + + adaptive_test = adt.TestAssembler( + item_pool=item_pool, + simulation_id="1", + participant_id="12", + ability_estimator=adt.MLEstimator, + content_balancing="WeightedPenaltyModel", + content_balancing_args={ + "constraints": [ + adt.Constraint( + "Math", + 0.5, + 0.2, + lower=0, + upper=1 + ), + adt.Constraint( + "English", + 0.5, + 0.1, + lower=0, + upper=1 + ) + ], + "constraint_weight": 0.5, + "information_weight": 0.5 + }, + debug=True + ) + + sim = adt.Simulation(adaptive_test, adt.ResultOutputFormat.CSV) + sim.simulate() + + +class TestExposureControl(unittest.TestCase): + def __init__(self, methodName="runTest"): + super().__init__(methodName) + + items = pd.DataFrame({ + "a": [1.32, 1.07, 0.84], + "b": [-0.63, 0.18, -0.84], + "c": [0.17, 0.10, 0.19], + "d": [0.87, 0.93, 1], + "id": [1, 2, 3] + }) + + self.available_items = adt.ItemPool.load_from_dataframe(items).test_items + self.content_categories = ["Math", "English", "Math"] + + for i, _ in enumerate(self.available_items): + self.available_items[i].additional_properties = { + "category": [self.content_categories[i]] + } + + def setUp(self): + def clean_up_sim(): + path = pathlib.Path("./data/1") + if path.exists(): + shutil.rmtree(path) + + self.addCleanup(clean_up_sim) + + def test_randomesque(self): + item_pool = adt.ItemPool(self.available_items, + [0, 1, 0]) + + adaptive_test = adt.TestAssembler( + item_pool=item_pool, + simulation_id="1", + participant_id="12", + ability_estimator=adt.MLEstimator, + exposure_control="Randomesque", + exposure_control_args={ # type: ignore + "n_items": 2, + "seed": None + }, + debug=True + ) + + sim = adt.Simulation(adaptive_test, adt.ResultOutputFormat.CSV) + sim.simulate() + + def test_MPI_exposure_control(self): + item_pool = adt.ItemPool(self.available_items, + [0, 1, 0]) + + ex_args: adt.ExposureControlArgs = { # type: ignore + "constraints": [ + adt.Constraint("Math", 0.5, 0.5), + adt.Constraint("English", 0.5, 0.5) + ], + "participant_ids": ["1"], + "output_format": adt.ResultOutputFormat.CSV + } + + def run_previous_tests(sim_id: str, par_id: str): + adaptive_test = adt.TestAssembler( + item_pool=item_pool, + simulation_id=sim_id, + participant_id=par_id, + ability_estimator=adt.MLEstimator, + debug=False + ) + + sim = adt.Simulation(adaptive_test, adt.ResultOutputFormat.CSV) + sim.simulate() + sim.save_test_results() + run_previous_tests("1", "1") + + # acutal test + adaptive_test = adt.TestAssembler( + item_pool=item_pool, + simulation_id="1", + participant_id="2", + ability_estimator=adt.MLEstimator, + exposure_control="MaximumPriorityIndex", + exposure_control_args=ex_args, + debug=False + ) + sim = adt.Simulation(adaptive_test, adt.ResultOutputFormat.CSV) + sim.simulate() + sim.save_test_results() + + def test_MPI_exposure_control_pickle(self): + item_pool = adt.ItemPool(self.available_items, + [0, 1, 0]) + + ex_args: adt.ExposureControlArgs = { # type: ignore + "constraints": [ + adt.Constraint("Math", 0.5, 0.5), + adt.Constraint("English", 0.5, 0.5) + ], + "participant_ids": ["1"], + "output_format": adt.ResultOutputFormat.PICKLE + } + + def run_previous_tests(sim_id: str, par_id: str): + adaptive_test = adt.TestAssembler( + item_pool=item_pool, + simulation_id=sim_id, + participant_id=par_id, + ability_estimator=adt.MLEstimator, + debug=False + ) + + sim = adt.Simulation(adaptive_test, adt.ResultOutputFormat.PICKLE) + sim.simulate() + sim.save_test_results() + run_previous_tests("1", "1") + + # acutal test + adaptive_test = adt.TestAssembler( + item_pool=item_pool, + simulation_id="1", + participant_id="2", + ability_estimator=adt.MLEstimator, + exposure_control="MaximumPriorityIndex", + exposure_control_args=ex_args, + debug=False + ) + sim = adt.Simulation(adaptive_test, adt.ResultOutputFormat.PICKLE) + sim.simulate() + sim.save_test_results() diff --git a/adaptivetesting/tests/test_generate_response_pattern.py b/adaptivetesting/tests/test_generate_response_pattern.py index 57d41ce..3bae53a 100644 --- a/adaptivetesting/tests/test_generate_response_pattern.py +++ b/adaptivetesting/tests/test_generate_response_pattern.py @@ -1,7 +1,7 @@ # flake8: noqa import unittest -import math -from adaptivetesting.models import ItemPool +import numpy as np +from adaptivetesting.models import ItemPool, TestItem from adaptivetesting.math.estimators import MLEstimator from adaptivetesting.math import generate_response_pattern @@ -36,6 +36,8 @@ 0.4029, -0.4667, 0.78, -0.0834], "c": [0.0597, 0.2406, 0.1503, 0.1288, 0.1006, 0.2201, 0.091, 0.0721, 0.0427, 0.043, 0.1205, 0.0632, 0.0541, 0.1686, 0.0119, 0.1752, 0.088, 0.1022, 0.2052, 0.2297, 0.0706, 0.2403, 0.1821, 0.1716, 0.0132, 0.0988, 0.1195, 0.1401, 0.1746, 0.2289, 0.1546, 0.1071, 0.1355, 0.0146, 0.0652, 0.0993, 0.0494, 0.208, 0.0382, 0.2009, 0.1367, 0.1656, 0.0429, 0.1583, 0.078, 0.1811, 0.0997, 0.2423, 0.2418, 0.1817], "d": [0.8143, 0.8054, 0.8983, 0.8169, 0.8828, 0.9463, 0.792, 0.8511, 0.8679, 0.967, 0.9814, 0.9705, 0.9185, 0.9875, 0.8791, 0.8941, 0.8341, 0.8368, 0.755, 0.8757, 0.9678, 0.7516, 0.768, 0.7911, 0.9426, 0.9338, 0.993, 0.8666, 0.7686, 0.9122, 0.9396, 0.7843, 0.8491, 0.8062, 0.7645, 0.849, 0.7662, 0.8065, 0.7637, 0.9176, 0.8244, 0.7752, 0.768, 0.9701, 0.9386, 0.9542, 0.9955, 0.7759, 0.7748, 0.9497]} + + class TestGenerateResponsePattern(unittest.TestCase): def test_compare_generation_to_estimation(self): item_pool = ItemPool.load_from_dict(source_dictionary) @@ -104,3 +106,32 @@ def test_calculate_expected_vs_actual(self): # The difference should be within reasonable bounds for random sampling # With 50 items, we expect some variation self.assertAlmostEqual(actual_percentage, expected_percentage, delta=3) + + +def make_polyt_item(a=1.0, b_list=None): + it = TestItem() + it.a = a + it.b = b_list if b_list is not None else [0.2, 0.7] + return it + +class TestGeneratePolyPattern(unittest.TestCase): + def test_no_break(self): + items = [make_polyt_item() for _ in range(3)] + pattern = generate_response_pattern(ability=0.5, items=items, model="GRM") + print(pattern) + + + def test_polytomous_requires_model(self): + items = [make_polyt_item() for _ in range(3)] + with self.assertRaises(ValueError): + generate_response_pattern(ability=0.0, items=items, model=None, seed=1) + + def test_polytomous_one_hot_and_reproducible(self): + items = [make_polyt_item(b_list=[-1.0, 0.0, 1.0]) for _ in range(4)] + r1 = generate_response_pattern(ability=0.5, items=items, model="GRM", seed=42) + r2 = generate_response_pattern(ability=0.5, items=items, model="GRM", seed=42) + + self.assertEqual(len(r1), len(items)) + + for a, b in zip(r1, r2): + self.assertTrue(np.array_equal(np.asarray(a), np.asarray(b))) diff --git a/adaptivetesting/tests/test_item_selection.py b/adaptivetesting/tests/test_item_selection.py index cf9f035..5cd40e2 100644 --- a/adaptivetesting/tests/test_item_selection.py +++ b/adaptivetesting/tests/test_item_selection.py @@ -48,7 +48,12 @@ def test_selection_when_0(self): 0 ) self.assertDictEqual(selected_item.as_dict(), - {"a": 1.0975, "b": 0.1836, "c": 0.053, "d": 0.7533}) + {"a": 1.0975, + "b": 0.1836, + "c": 0.053, + "d": 0.7533, + "additional_properties": {}, + "id": None}) def test_selection_when_minus_0_5(self): items = self.load_items() @@ -57,4 +62,9 @@ def test_selection_when_minus_0_5(self): -0.5 ) self.assertDictEqual(selected_item.as_dict(), - {"a": 1.1477, "b": -0.8356, "c": 0.1629, "d": 0.8456}) + {"a": 1.1477, + "b": -0.8356, + "c": 0.1629, + "d": 0.8456, + "additional_properties": {}, + "id": None}) diff --git a/adaptivetesting/tests/test_load_test_items.py b/adaptivetesting/tests/test_load_test_items.py index 91c8fa2..12cf26e 100644 --- a/adaptivetesting/tests/test_load_test_items.py +++ b/adaptivetesting/tests/test_load_test_items.py @@ -1,3 +1,4 @@ +# flake8: noqa from unittest import TestCase from adaptivetesting.models import TestItem, ItemPool import pandas as pd @@ -96,7 +97,9 @@ def test_load_items_from_pandas_success(self): "a": 0.9, "b": 5, "c": 0.9, - "d": 1 + "d": 1, + "additional_properties": {}, + "id": None }, generated.test_items[0].as_dict() ) @@ -106,7 +109,9 @@ def test_load_items_from_pandas_success(self): "a": 1.9, "b": 3, "c": 1.9, - "d": 1 + "d": 1, + "additional_properties": {}, + "id": None }, generated.test_items[1].as_dict() ) @@ -133,7 +138,8 @@ def test_load_items_from_pandas_with_ids_success(self): "b": 5, "c": 0.9, "d": 1, - "id": 101 + "id": 101, + "additional_properties": {} }, generated.test_items[0].as_dict(with_id=True) ) @@ -144,7 +150,8 @@ def test_load_items_from_pandas_with_ids_success(self): "b": 3, "c": 1.9, "d": 1, - "id": 202 + "id": 202, + "additional_properties": {} }, generated.test_items[1].as_dict(with_id=True) ) @@ -158,9 +165,23 @@ def test_load_items_pandas_error_missing_column(self): "c": [0.9, 1.9] } df = pd.DataFrame(dictionary) + # this should work because d can be ignored when creating items + pool = ItemPool.load_from_dataframe(df) + # check that the pool contains the correct items + item1 = TestItem() + item1.a = 0.9 + item1.b = 5 + item1.c = 0.9 + item1.d = 1 - with self.assertRaises(ValueError): - ItemPool.load_from_dataframe(df) + item2 = TestItem() + item2.a = 1.9 + item2.b = 3 + item2.c = 1.9 + item2.d = 1 + + self.assertDictEqual(item1.as_dict(), pool.test_items[0].as_dict()) + self.assertDictEqual(item2.as_dict(), pool.test_items[1].as_dict()) def test_load_pandas_no_responses(self): dictionary = { @@ -174,3 +195,131 @@ def test_load_pandas_no_responses(self): generated = ItemPool.load_from_dataframe(df) self.assertIsNone(generated.simulated_responses) + + def test_load_dict_content_balancing(self): + source_dictionary: dict[str, list[float]] = { + "a": [0.9, 1.9], + "b": [5, 3], + "c": [0.9, 1.9], + "d": [1, 1] + } + + item_pool = ItemPool.load_from_dict(source=source_dictionary, + content_categories=[["math"], ["english"]]) + items = item_pool.test_items + assigned_groups = [item.additional_properties["category"] for item in items] + + self.assertListEqual(assigned_groups, [["math"], ["english"]]) + + def test_load_list_content_balancing(self): + source_dictionary: dict[str, list[float] | list[int] | list[list[str]]] = { + "a": [0.9, 1.9], + "b": [5, 3], + "c": [0.9, 1.9], + "d": [1, 1], + "group": [["math"], ["english"]] + } + + item_pool = ItemPool.load_from_list( + a=source_dictionary["a"], # type: ignore + b=source_dictionary["b"], # type: ignore + c=source_dictionary["c"], # type: ignore + d=source_dictionary["d"], # type: ignore + content_categories=source_dictionary["group"] # type: ignore + ) + items = item_pool.test_items + assigned_groups = [item.additional_properties["category"] for item in items] + + self.assertListEqual(assigned_groups, [["math"], ["english"]]) + + def test_load_dataframe_content_balancing(self): + source_dictionary: dict[str, list[float] | list[int] | list[list[str]]] = { + "a": [0.9, 1.9], + "b": [5, 3], + "c": [0.9, 1.9], + "d": [1, 1], + "content_categories": [["math"], ["english"]] + } + + item_pool = ItemPool.load_from_dataframe(pd.DataFrame(source_dictionary)) + items = item_pool.test_items + assigned_groups = [item.additional_properties["category"] for item in items] + + self.assertListEqual(assigned_groups, [["math"], ["english"]]) + + +class TestTestItemRoundTrip(TestCase): + def test_roundtrip_preserves_fields(self): + # create and populate original item + original = TestItem() + original.id = 42 + original.a = 1.2 + original.b = -0.5 + original.c = 0.25 + original.d = 0.95 + original.additional_properties = { + "category": ["Math", "Science"], + "meta": {"difficulty": "hard", "tags": ["algebra", "geometry"]}, + } + + # serialize including id + data_with_id = original.as_dict() + + # deserialize + restored = TestItem.from_dict(data_with_id) + + # verify fields preserved + self.assertEqual(restored.id, original.id) + self.assertEqual(restored.a, original.a) + self.assertEqual(restored.b, original.b) + self.assertEqual(restored.c, original.c) + self.assertEqual(restored.d, original.d) + self.assertEqual(restored.additional_properties, original.additional_properties) + + +class TestPolyItems(TestCase): + def test_loading_items_list(self): + items = ItemPool.load_from_list( + a = [0.934, 0.972, 1.210], + b = [ + [0.071, 0.129], + [1.715, 0.461], + [-1.265, -0.687] + ] + ).test_items + + self.assertTrue(all([isinstance(item.a, float) for item in items])) + self.assertTrue(all([isinstance(item.b, list) for item in items])) + + def test_loading_items_dict(self): + items_dict: dict[str, list] = { + "a" : [0.934, 0.972, 1.210], + "b": [ + [0.071, 0.129], + [1.715, 0.461], + [-1.265, -0.687] + ] + } + + items = ItemPool.load_from_dict( + items_dict + ).test_items + + self.assertTrue(all([isinstance(item.a, float) for item in items])) + self.assertTrue(all([isinstance(item.b, list) for item in items])) + + def test_loading_items_df(self): + items_dict = { + "a" : [0.934, 0.972, 1.210], + "b": [ + [0.071, 0.129], + [1.715, 0.461], + [-1.265, -0.687] + ] + } + + df = pd.DataFrame(items_dict) + items = ItemPool.load_from_dataframe(df).test_items + + self.assertTrue(all([isinstance(item.a, float) for item in items])) + self.assertTrue(all([isinstance(item.b, list) for item in items])) diff --git a/adaptivetesting/tests/test_poly_models.py b/adaptivetesting/tests/test_poly_models.py new file mode 100644 index 0000000..7043fc6 --- /dev/null +++ b/adaptivetesting/tests/test_poly_models.py @@ -0,0 +1,103 @@ +# flake8: noqa +import adaptivetesting as adt +import unittest + +class TestPolyMLEstimation(unittest.TestCase): + def test_grm(self): + items = adt.ItemPool.load_from_list( + a = [0.943, 0.972, 1.210], + b = [ + [0.071, 0.129], + [0.461, 1.715], + [-1.265, -0.687] + ] + ).test_items + + pattern = [2, 1, 2] + estimator = adt.MLEstimator( + response_pattern=pattern, + items=items, + model="GRM" + ) + estimate = estimator.get_estimation() + print(estimate) + self.assertAlmostEqual(1.6684, round(estimate, 3), delta=0.001) + + pattern = [0, 1, 2] + estimator = adt.MLEstimator( + response_pattern=pattern, + items=items, + model="GRM" + ) + estimate = estimator.get_estimation() + self.assertAlmostEqual(0.4076371, estimate, delta=0.01) + + def test_gpcm(self): + items = adt.ItemPool.load_from_list( + a = [0.934, 0.972, 1.210], + b = [ + [0.071, 0.129], + [1.715, 0.461], + [-1.265, -0.687] + ] + ).test_items + + pattern = [2,1,2] + estimator = adt.MLEstimator( + pattern, + items, + "GPCM" + ) + estimate = estimator.get_estimation() + self.assertAlmostEqual( + 1.581, + estimate, + delta=0.001 + ) + + pattern = [0, 1, 2] + estimator = adt.MLEstimator( + pattern, + items, + "GPCM" + ) + estimate = estimator.get_estimation() + self.assertAlmostEqual( + 0.181, + estimate, + delta=0.001 + ) + + def test_gpcm_information(self): + items = adt.ItemPool.load_from_list( + a = [0.934, 0.972, 1.210], + b = [ + [0.071, 0.129], + [1.715, 0.461], + [-1.265, -0.687] + ] + ).test_items + + pattern = [2, 1, 2] # required for spec, has no influence on the result + estimator = adt.MLEstimator(pattern, + items, + "GPCM") + sde = estimator.get_standard_error(0) + self.assertAlmostEqual(sde, 0.819, delta=0.001) + + def test_grm_information(self): + items = adt.ItemPool.load_from_list( + a = [0.943, 0.972, 1.210], + b = [ + [0.071, 0.129], + [0.461, 1.715], + [-1.265, -0.687] + ] + ).test_items + + pattern = [2, 1, 2] # required for spec, has no influence on the result + estimator = adt.MLEstimator(pattern, + items, + "GRM") + sde = estimator.get_standard_error(0) + self.assertAlmostEqual(sde, 1.133, delta=0.003) diff --git a/adaptivetesting/tests/test_priors.py b/adaptivetesting/tests/test_priors.py new file mode 100644 index 0000000..bb056b3 --- /dev/null +++ b/adaptivetesting/tests/test_priors.py @@ -0,0 +1,56 @@ +import unittest +import numpy as np +from adaptivetesting.math.estimators import EmpiricalPrior, SkewNormalPrior + + +class TestEmpiricalPrior(unittest.TestCase): + def setUp(self): + self.rng = np.random.default_rng(0) + # univariate dataset of moderate size to avoid singular covariance + self.dataset = self.rng.normal(loc=0.0, scale=1.0, size=200) + + def test_pdf_array_and_scalar(self): + prior = EmpiricalPrior(self.dataset) + points = np.array([-1.0, 0.0, 1.0]) + dens = prior.pdf(points) + # gaussian_kde returns an array of densities for array input + self.assertEqual(np.asarray(dens).shape[-1], points.shape[-1]) + self.assertTrue(np.all(np.asarray(dens) >= 0.0)) + + # scalar input - ensure convertible to float and non-negative + scalar_d = prior.pdf(0.0) + scalar_val = float(np.asarray(scalar_d).ravel()[0]) + self.assertTrue(np.isfinite(scalar_val)) + self.assertGreaterEqual(scalar_val, 0.0) + + def test_pdf_peak_near_mean(self): + prior = EmpiricalPrior(self.dataset) + mean = float(np.mean(self.dataset)) + dens_mean = float(np.asarray(prior.pdf(np.array([mean]))).ravel()[0]) + dens_far = float(np.asarray(prior.pdf(np.array([mean + 5.0]))).ravel()[0]) + self.assertGreater(dens_mean, dens_far) + + +class TestSkewNormalPrior(unittest.TestCase): + def test_pdf_scalar_and_array(self): + prior = SkewNormalPrior(skewness=2.0, loc=0.0, scale=1.0) + scalar = prior.pdf(0.0) + scalar_val = float(np.asarray(scalar).ravel()[0]) if hasattr(scalar, "__array__") else float(scalar) + self.assertTrue(np.isfinite(scalar_val)) + self.assertGreaterEqual(scalar_val, 0.0) + + arr = np.array([-3.0, 0.0, 3.0]) + dens_arr = prior.pdf(arr) + dens_arr = np.asarray(dens_arr) + self.assertEqual(dens_arr.shape[-1], arr.shape[-1]) + self.assertTrue(np.all(dens_arr >= 0.0)) + + def test_pdf_decreases_far_from_loc(self): + prior = SkewNormalPrior(skewness=0.0, loc=1.0, scale=0.5) + dens_loc = float(np.asarray(prior.pdf(1.0)).ravel()[0]) + dens_far = float(np.asarray(prior.pdf(1.0 + 5.0)).ravel()[0]) + self.assertGreater(dens_loc, dens_far) + + +if __name__ == "__main__": + unittest.main() diff --git a/adaptivetesting/tests/test_simulation.py b/adaptivetesting/tests/test_simulation.py index bd056a0..7634a61 100644 --- a/adaptivetesting/tests/test_simulation.py +++ b/adaptivetesting/tests/test_simulation.py @@ -3,6 +3,8 @@ from adaptivetesting.simulation.__simulation import Simulation from adaptivetesting.models.__adaptive_test import AdaptiveTest from adaptivetesting.models.__misc import ResultOutputFormat, StoppingCriterion +import pandas as pd +import adaptivetesting as adt def get_mock_adaptive_test(): @@ -32,7 +34,7 @@ def get_mock_adaptive_test_empty_pool(): return mock_test -class TestSimulation(unittest.TestCase): +class TestSimulationMock(unittest.TestCase): @patch("adaptivetesting.simulation.__simulation.PickleContext") @patch("adaptivetesting.simulation.__simulation.CSVContext") @@ -97,3 +99,63 @@ def test_save_test_results_unsupported_format(self): sim = Simulation(test=mock_adaptive_test, test_result_output="UNSUPPORTED") # type: ignore with self.assertRaises(KeyError): sim.save_test_results() + + +class TestFullSimulation(unittest.TestCase): + def test_run_basic_simulation_GRM(self): + items = pd.DataFrame({ + "a": [1.32, 1.07, 0.84], + "b": [[0.2, 0.9], + [0.2, 0.9], + [0.2, 0.9]], + "id": [1, 2, 3] + }) + + item_pool = adt.ItemPool.load_from_dataframe(items) + res_pattern = adt.generate_response_pattern( + 0, + item_pool.test_items, + model="GRM", + seed=123 + ) + item_pool.simulated_responses = res_pattern + + adaptive_test = adt.TestAssembler( + item_pool=item_pool, + simulation_id="2", + participant_id="2", + ability_estimator=adt.MLEstimator, + model_type="GRM" + ) + + sim = adt.Simulation(adaptive_test, adt.ResultOutputFormat.CSV) + sim.simulate() + + def test_run_basic_simulation_GPCM(self): + items = pd.DataFrame({ + "a": [0.926, 1.595, 0.330], + "b": [[1.595, 0.330], + [-0.820, 0.487], + [0.738, 0.578]], + "id": [1, 2, 3] + }) + + item_pool = adt.ItemPool.load_from_dataframe(items) + res_pattern = adt.generate_response_pattern( + 0, + item_pool.test_items, + model="GPCM", + seed=123 + ) + item_pool.simulated_responses = res_pattern + + adaptive_test = adt.TestAssembler( + item_pool=item_pool, + simulation_id="2", + participant_id="2", + ability_estimator=adt.MLEstimator, + model_type="GPCM" + ) + + sim = adt.Simulation(adaptive_test, adt.ResultOutputFormat.CSV) + sim.simulate() diff --git a/adaptivetesting/tests/test_test_assembler.py b/adaptivetesting/tests/test_test_assembler.py index 4a09d7e..39b764d 100644 --- a/adaptivetesting/tests/test_test_assembler.py +++ b/adaptivetesting/tests/test_test_assembler.py @@ -11,7 +11,7 @@ class DummyTestItem(TestItem): def __init__(self, id=0): self.id = id - def as_dict(self, with_id: bool = True) -> dict[str, float | int | None]: + def as_dict(self, with_id: bool = True): return {"id": self.id} @@ -57,7 +57,7 @@ def setUp(self): simulation_id="sim1", participant_id="p1", ability_estimator=DummyEstimator, - estimator_args={}, + estimator_args={}, # type: ignore item_selector=dummy_item_selector, item_selector_args={}, pretest=False, @@ -71,7 +71,7 @@ def test_init_sets_attributes(self): simulation_id="sim1", participant_id="p1", ability_estimator=DummyEstimator, - estimator_args={"foo": "bar"}, + estimator_args={"foo": "bar"}, # type: ignore item_selector=dummy_item_selector, item_selector_args={"baz": 1}, pretest=True, @@ -80,7 +80,7 @@ def test_init_sets_attributes(self): debug=True ) self.assertEqual(assembler._TestAssembler__ability_estimator, DummyEstimator) # type: ignore - self.assertEqual(assembler._TestAssembler__estimator_args, {"foo": "bar"}) # type: ignore + self.assertEqual(assembler._TestAssembler__estimator_args, {"foo": "bar", "model": None}) # type: ignore self.assertEqual(assembler._TestAssembler__item_selector, dummy_item_selector) # type: ignore self.assertEqual(assembler._TestAssembler__item_selector_args, {"baz": 1}) # type: ignore self.assertTrue(assembler._TestAssembler__pretest) # type: ignore @@ -99,7 +99,7 @@ def test_estimate_ability_level_all_correct(self): simulation_id="sim1", participant_id="p1", ability_estimator=DummyEstimator, - estimator_args={}, + estimator_args={}, # type: ignore item_selector=dummy_item_selector, item_selector_args={}, pretest=False, @@ -120,7 +120,7 @@ def test_estimate_ability_level_all_incorrect(self): simulation_id="sim1", participant_id="p1", ability_estimator=DummyEstimator, - estimator_args={}, + estimator_args={}, # type: ignore item_selector=dummy_item_selector, item_selector_args={}, pretest=False, @@ -141,7 +141,7 @@ def test_estimate_ability_level_raises_on_other_exception(self): simulation_id="sim1", participant_id="p1", ability_estimator=DummyEstimator, - estimator_args={}, + estimator_args={}, # type: ignore item_selector=dummy_item_selector, item_selector_args={}, pretest=False, @@ -168,7 +168,7 @@ def test_run_test_once_calls_super(self): simulation_id="sim1", participant_id="p1", ability_estimator=DummyEstimator, - estimator_args={}, + estimator_args={}, # type: ignore item_selector=dummy_item_selector, item_selector_args={}, pretest=True, diff --git a/adaptivetesting/tests/test_weighted_penalty_model.py b/adaptivetesting/tests/test_weighted_penalty_model.py new file mode 100644 index 0000000..e18841a --- /dev/null +++ b/adaptivetesting/tests/test_weighted_penalty_model.py @@ -0,0 +1,530 @@ +# type: ignore +import unittest +import pandas as pd +import adaptivetesting as adt +import copy +from typing import Literal + + +class MockItem(adt.TestItem): + def __init__(self, category: list[str]): + super().__init__() + self.additional_properties["category"] = category + + +class TestWeightedPenaltyModel(unittest.TestCase): + def __init__(self, methodName="runTest"): + super().__init__(methodName) + + # load test item pool + data_frame = pd.read_json("adaptivetesting/tests/example_item_pool.json") + # convert list[dict] into item pool + self.item_pool = adt.ItemPool.load_from_dataframe(data_frame) + + # create two example items fitting a rasch model + self.example_item1 = adt.TestItem() + self.example_item1.id = 1 + self.example_item1.a = 1 + self.example_item1.b = 0.5 + self.example_item1.c = 0 + self.example_item1.d = 1 + self.example_item1.additional_properties["category"] = ["math"] + + self.example_item2 = adt.TestItem() + self.example_item2.id = 2 + self.example_item2.a = 1 + self.example_item2.b = 0.5 + self.example_item2.c = 0 + self.example_item2.d = 1 + self.example_item2.additional_properties["category"] = ["english"] + + def test_content_penalty_calculation(self): + """compute_total_content_penalty_value_for_item""" + # create target item + item = copy.deepcopy(self.example_item1) + item.additional_properties["category"] = ["math", "science"] + + # create shown items for math and science + shown_items = [ + MockItem(["math"]), + MockItem(["math"]), + MockItem(["science"]) + ] + + # setup constraints + constraints = [ + adt.Constraint( + name="math", + prevalence=0.75, + lower=0, + upper=1, + weight=1 + ), + adt.Constraint( + name="science", + prevalence=0.25, + lower=0, + upper=1, + weight=1 + ) + ] + + total_content_penalty_value = adt.compute_total_content_penalty_value_for_item( + item, + shown_items=shown_items, + available_items=[item], + constraints=constraints + ) + + manual_result = 0.4166 - 0.083 + + self.assertAlmostEqual(total_content_penalty_value, + manual_result, places=2) + + def test_calcualte_weighted_content_penalty(self): + """calculate_weighted_penalty_value""" + item_information = 0.5 + max_information = 1 + constraint_weight = 1 + information_weight = 1 + total_content_penalty = 0.5 + maximum_total_content_penalty = 0.8 + minimum_total_content_penalty = 0.2 + + # standardize total content constraint penalty value + standardized_total_content_penalty_value = adt.standardize_total_content_constraint_penalty_value( + item_penalty_value=total_content_penalty, + minimum=minimum_total_content_penalty, + maximum=maximum_total_content_penalty + ) + + self.assertAlmostEqual(standardized_total_content_penalty_value, 0.5, places=2) + + # standardize item information + standardized_item_information = adt.standardize_item_information( + item_information=item_information, + maximum=max_information + ) + self.assertAlmostEqual(standardized_item_information, 0.5, places=2) + + # calculate information penalty value + information_penalty_value = adt.compute_information_penalty_value( + standardized_item_information + ) + + self.assertAlmostEqual(information_penalty_value, -0.25, places=2) + + # compute weighted penalty vlaue + weighted_penalty_value = adt.compute_weighted_penalty_value( + constraint_weight=constraint_weight, + standardized_constraint_penalty_value=standardized_total_content_penalty_value, + information_weight=information_weight, + information_penalty_value=information_penalty_value + ) + + self.assertAlmostEqual(weighted_penalty_value, 0.25, places=2) + + def test_constraint_group_assignment(self): + """get_constraint_group_assignments""" + + # setup constraints + constraints = [ + adt.Constraint( + name="math", + prevalence=0.75, + lower=0, + upper=1, + weight=1 + ), + adt.Constraint( + name="science", + prevalence=0.25, + lower=0.9, + upper=1, + weight=1 + ) + ] + + assignments = [] + for constraint in constraints: + # calculate proportion + prop = adt.compute_prop( + n_administered=1, + n_remaining=1, + prevalence=constraint.prevalence, + test_length=2 + ) + + # assign color group per proportion + _, assignment = adt.WeightedPenaltyModel.assign_color_group_per_proportion( + constraint, + prop + ) + assignments.append(assignment) + + self.assertListEqual(assignments, ["B", "A"]) + + def test_candidate_group_assignment(self): + """form_list_of_candidate_items""" + # create item + item = MockItem("None") + weighted_penalty_value = float("NaN") + # test green + associated_constraints: list[tuple[adt.Constraint, Literal['A', 'B', 'C']]] = [ + (adt.Constraint(None, None, None), "A"), + (adt.Constraint(None, None, None), "B") + ] + _, _, assigned_group = adt.WeightedPenaltyModel.assign_items_to_item_group( + item, associated_constraints, + weighted_penalty_value + ) + self.assertEqual(assigned_group, "green") + + # test organge + associated_constraints: list[tuple[adt.Constraint, Literal['A', 'B', 'C']]] = [ + (adt.Constraint(None, None, None), "A"), + (adt.Constraint(None, None, None), "C") + ] + _, _, assigned_group = adt.WeightedPenaltyModel.assign_items_to_item_group( + item, associated_constraints, + weighted_penalty_value + ) + self.assertEqual(assigned_group, "orange") + + # test yellow + associated_constraints: list[tuple[adt.Constraint, Literal['A', 'B', 'C']]] = [ + (adt.Constraint(None, None, None), "B"), + (adt.Constraint(None, None, None), "B") + ] + _, _, assigned_group = adt.WeightedPenaltyModel.assign_items_to_item_group( + item, associated_constraints, + weighted_penalty_value + ) + self.assertEqual(assigned_group, "yellow") + + # test red + associated_constraints: list[tuple[adt.Constraint, Literal['A', 'B', 'C']]] = [ + (adt.Constraint(None, None, None), "B"), + (adt.Constraint(None, None, None), "C") + ] + _, _, assigned_group = adt.WeightedPenaltyModel.assign_items_to_item_group( + item, associated_constraints, + weighted_penalty_value + ) + self.assertEqual(assigned_group, "red") + + def test_select_item_with_no_shown_items(self): + """Test that select_item returns the highest information item when no previous items have been shown""" + # Create a mock AdaptiveTest with no shown items + class MockAdaptiveTest: + def __init__(self, item_pool, ability_level): + self.item_pool = item_pool + self.ability_level = ability_level + self.answered_items = [] # No items shown + + # Create item pool with example items + item_pool_obj = adt.ItemPool([self.example_item1, self.example_item2]) + + # Create mock adaptive test with empty answered_items + mock_test = MockAdaptiveTest(item_pool_obj, 0) + + # Create constraints + constraints = [ + adt.Constraint( + name="math", + prevalence=0.5, + lower=0, + upper=1, + weight=1 + ), + adt.Constraint( + name="english", + prevalence=0.5, + lower=0, + upper=1, + weight=1 + ) + ] + + # Create WeightedPenaltyModel + model = adt.WeightedPenaltyModel( + adaptive_test=mock_test, + constraints=constraints, + constraint_weight=1.0, + information_weight=1.0 + ) + + # Select item + selected_item = model.select_item() + + # select item using maximum fisher information + information_selected_item: adt.TestItem = adt.maximum_information_criterion( + items=item_pool_obj.test_items, + ability=0 + ) + + # Verify an item is returned + self.assertIsNotNone(selected_item) + self.assertIsInstance(selected_item, adt.TestItem) + + self.assertDictEqual( + selected_item.as_dict(), + information_selected_item.as_dict() + ) + + +class TestWeightedPenaltyModelPoly(unittest.TestCase): + def __init__(self, methodName="runTest"): + super().__init__(methodName) + + # load test item pool + data_frame = pd.read_json("adaptivetesting/tests/example_item_pool.json") + # convert list[dict] into item pool + self.item_pool = adt.ItemPool.load_from_dataframe(data_frame) + + # create two example items fitting a rasch model + self.example_item1 = adt.TestItem() + self.example_item1.id = 1 + self.example_item1.a = 1 + self.example_item1.b = [0.5, 0.9] + self.example_item1.additional_properties["category"] = ["math"] + + self.example_item2 = adt.TestItem() + self.example_item2.id = 2 + self.example_item2.a = 1 + self.example_item2.b = [0.5, 0.9] + self.example_item2.additional_properties["category"] = ["english"] + + def test_content_penalty_calculation(self): + """compute_total_content_penalty_value_for_item""" + # create target item + item = copy.deepcopy(self.example_item1) + item.additional_properties["category"] = ["math", "science"] + + # create shown items for math and science + shown_items = [ + MockItem(["math"]), + MockItem(["math"]), + MockItem(["science"]) + ] + + # setup constraints + constraints = [ + adt.Constraint( + name="math", + prevalence=0.75, + lower=0, + upper=1, + weight=1 + ), + adt.Constraint( + name="science", + prevalence=0.25, + lower=0, + upper=1, + weight=1 + ) + ] + + total_content_penalty_value = adt.compute_total_content_penalty_value_for_item( + item, + shown_items=shown_items, + available_items=[item], + constraints=constraints + ) + + manual_result = 0.4166 - 0.083 + + self.assertAlmostEqual(total_content_penalty_value, + manual_result, places=2) + + def test_calcualte_weighted_content_penalty(self): + """calculate_weighted_penalty_value""" + item_information = 0.5 + max_information = 1 + constraint_weight = 1 + information_weight = 1 + total_content_penalty = 0.5 + maximum_total_content_penalty = 0.8 + minimum_total_content_penalty = 0.2 + + # standardize total content constraint penalty value + standardized_total_content_penalty_value = adt.standardize_total_content_constraint_penalty_value( + item_penalty_value=total_content_penalty, + minimum=minimum_total_content_penalty, + maximum=maximum_total_content_penalty + ) + + self.assertAlmostEqual(standardized_total_content_penalty_value, 0.5, places=2) + + # standardize item information + standardized_item_information = adt.standardize_item_information( + item_information=item_information, + maximum=max_information + ) + self.assertAlmostEqual(standardized_item_information, 0.5, places=2) + + # calculate information penalty value + information_penalty_value = adt.compute_information_penalty_value( + standardized_item_information + ) + + self.assertAlmostEqual(information_penalty_value, -0.25, places=2) + + # compute weighted penalty vlaue + weighted_penalty_value = adt.compute_weighted_penalty_value( + constraint_weight=constraint_weight, + standardized_constraint_penalty_value=standardized_total_content_penalty_value, + information_weight=information_weight, + information_penalty_value=information_penalty_value + ) + + self.assertAlmostEqual(weighted_penalty_value, 0.25, places=2) + + def test_constraint_group_assignment(self): + """get_constraint_group_assignments""" + + # setup constraints + constraints = [ + adt.Constraint( + name="math", + prevalence=0.75, + lower=0, + upper=1, + weight=1 + ), + adt.Constraint( + name="science", + prevalence=0.25, + lower=0.9, + upper=1, + weight=1 + ) + ] + + assignments = [] + for constraint in constraints: + # calculate proportion + prop = adt.compute_prop( + n_administered=1, + n_remaining=1, + prevalence=constraint.prevalence, + test_length=2 + ) + + # assign color group per proportion + _, assignment = adt.WeightedPenaltyModel.assign_color_group_per_proportion( + constraint, + prop + ) + assignments.append(assignment) + + self.assertListEqual(assignments, ["B", "A"]) + + def test_candidate_group_assignment(self): + """form_list_of_candidate_items""" + # create item + item = MockItem("None") + weighted_penalty_value = float("NaN") + # test green + associated_constraints: list[tuple[adt.Constraint, Literal['A', 'B', 'C']]] = [ + (adt.Constraint(None, None, None), "A"), + (adt.Constraint(None, None, None), "B") + ] + _, _, assigned_group = adt.WeightedPenaltyModel.assign_items_to_item_group( + item, associated_constraints, + weighted_penalty_value + ) + self.assertEqual(assigned_group, "green") + + # test organge + associated_constraints: list[tuple[adt.Constraint, Literal['A', 'B', 'C']]] = [ + (adt.Constraint(None, None, None), "A"), + (adt.Constraint(None, None, None), "C") + ] + _, _, assigned_group = adt.WeightedPenaltyModel.assign_items_to_item_group( + item, associated_constraints, + weighted_penalty_value + ) + self.assertEqual(assigned_group, "orange") + + # test yellow + associated_constraints: list[tuple[adt.Constraint, Literal['A', 'B', 'C']]] = [ + (adt.Constraint(None, None, None), "B"), + (adt.Constraint(None, None, None), "B") + ] + _, _, assigned_group = adt.WeightedPenaltyModel.assign_items_to_item_group( + item, associated_constraints, + weighted_penalty_value + ) + self.assertEqual(assigned_group, "yellow") + + # test red + associated_constraints: list[tuple[adt.Constraint, Literal['A', 'B', 'C']]] = [ + (adt.Constraint(None, None, None), "B"), + (adt.Constraint(None, None, None), "C") + ] + _, _, assigned_group = adt.WeightedPenaltyModel.assign_items_to_item_group( + item, associated_constraints, + weighted_penalty_value + ) + self.assertEqual(assigned_group, "red") + + def test_select_item_with_no_shown_items(self): + """Test that select_item returns the highest information item when no previous items have been shown""" + # Create a mock AdaptiveTest with no shown items + class MockAdaptiveTest: + def __init__(self, item_pool, ability_level): + self.item_pool = item_pool + self.ability_level = ability_level + self.answered_items = [] # No items shown + + # Create item pool with example items + item_pool_obj = adt.ItemPool([self.example_item1, self.example_item2]) + + # Create mock adaptive test with empty answered_items + mock_test = MockAdaptiveTest(item_pool_obj, 0) + + # Create constraints + constraints = [ + adt.Constraint( + name="math", + prevalence=0.5, + lower=0, + upper=1, + weight=1 + ), + adt.Constraint( + name="english", + prevalence=0.5, + lower=0, + upper=1, + weight=1 + ) + ] + + # Create WeightedPenaltyModel + model = adt.WeightedPenaltyModel( + adaptive_test=mock_test, + constraints=constraints, + constraint_weight=1.0, + information_weight=1.0 + ) + + # Select item + selected_item = model.select_item() + + # select item using maximum fisher information + information_selected_item: adt.TestItem = adt.maximum_information_criterion( + items=item_pool_obj.test_items, + ability=0 + ) + + # Verify an item is returned + self.assertIsNotNone(selected_item) + self.assertIsInstance(selected_item, adt.TestItem) + + self.assertDictEqual( + selected_item.as_dict(), + information_selected_item.as_dict() + ) diff --git a/adaptivetesting/utils/__funcs.py b/adaptivetesting/utils/__funcs.py index f5dd034..8c678dc 100644 --- a/adaptivetesting/utils/__funcs.py +++ b/adaptivetesting/utils/__funcs.py @@ -34,7 +34,7 @@ def load_final_test_results(simulation_id: str, final_result = test_results[-1] final_test_results.append(final_result) - if output_format is ResultOutputFormat.PICKLE: + elif output_format is ResultOutputFormat.PICKLE: for id in participant_ids: context = PickleContext(simulation_id, participant_id=id) test_results = context.load() diff --git a/adaptivetesting/utils/__plots.py b/adaptivetesting/utils/__plots.py index 385acb4..3ae0ac4 100644 --- a/adaptivetesting/utils/__plots.py +++ b/adaptivetesting/utils/__plots.py @@ -7,6 +7,7 @@ from ..math.estimators.__test_information import item_information_function from .__funcs import load_final_test_results, load_test_results_single_participant import numpy as np +from typing import Literal def plot_final_ability_estimates(simulation_id: str, @@ -37,18 +38,22 @@ def plot_final_ability_estimates(simulation_id: str, # read final test results data final_test_results = load_final_test_results(simulation_id, participant_ids, output_format) # extract true and finally estimated ability levels - true_and_final_abilities = [ - (result.ability_estimation, result.true_ability_level) - for result in final_test_results - ] + estimates = [] + true_abilities = [] + + for result in final_test_results: + estimates.append(result.ability_estimation) + true_abilities.append(result.true_ability_level) - final_estimates, true_abilities = zip(*true_and_final_abilities) - if "color" not in kwargs: - ax.scatter(true_abilities, final_estimates, color="blue", **kwargs) + ax.scatter(np.array(true_abilities, dtype=float), + np.array(estimates, dtype=float), + color="blue", **kwargs) else: - ax.scatter(true_abilities, final_estimates, **kwargs) - ax.plot(true_abilities, true_abilities, color="black") + ax.scatter(np.array(true_abilities, dtype=float), + np.array(estimates, dtype=float), **kwargs) + ax.plot(np.array(true_abilities, dtype=float), + np.array(true_abilities, dtype=float), color="black") ax.set_xlabel("True ability level") ax.set_ylabel("Estimated ability level") @@ -69,7 +74,7 @@ def plot_icc(item: TestItem, Returns: tuple: A tuple containing the matplotlib Figure and Axes objects. """ - thetas = np.linspace(range[0], range[1], 1000) + thetas = np.linspace(range[0], range[1], 1000, dtype=float) probabilities = probability_y1( mu=np.array(thetas).T, a=np.array(item.a), @@ -94,6 +99,7 @@ def plot_icc(item: TestItem, def plot_iif(item: TestItem, range: tuple[float, float] = (-10, 10), + model: Literal["GRM", "GPCM"] | None = None, ax: Axes | None = None, **kwargs): """ @@ -101,6 +107,7 @@ def plot_iif(item: TestItem, Parameters: item (TestItem): The test item for which to plot the information function. range (tuple[float, float], optional): The range of ability levels (theta) to plot over. Defaults to (-10, 10). + model (Literal["GRM", "GPCM"], optional): Type of IRT model. Defaults to dichotomous IRT models. ax (Axes, optional): Matplotlib Axes object to plot on. If None, a new figure and axes are created. **kwargs: Additional keyword arguments passed to matplotlib's plot function. Returns: @@ -113,11 +120,9 @@ def plot_iif(item: TestItem, for theta in thetas: info = item_information_function( - mu=theta, - a=np.array(item.a), - b=np.array(item.b), - c=np.array(item.c), - d=np.array(item.d), + ability=theta.astype(float).item(), + item=item, + model=model ) information_array.append(info) @@ -141,7 +146,7 @@ def plot_exposure_rate(simulation_id: str, in a series of adaptive tests or CAT simulations. Args: - simulation_id (str): Simulation identifyer + simulation_id (str): Simulation identifier participant_ids (list[str]): List of unique participant IDs output_format (ResultOutputFormat): Format in which the test results have been previously saved @@ -203,6 +208,7 @@ def plot_exposure_rate(simulation_id: str, def plot_test_information( items: list[TestItem], range: tuple[float, float] = (-10, 10), + model: Literal["GRM", "GPCM"] | None = None, ax: Axes | None = None, **kwargs): """ @@ -210,21 +216,21 @@ def plot_test_information( Args: items (list[TestItem]): Test items in an item pool for which to calculate the test information range (tuple[float, float], optional): The range of ability levels (theta) to plot over. Defaults to (-10, 10). + model (Literal["GRM", "GPCM"], optional): Type of IRT model. Defaults to dichotomous IRT models. ax (Axes, optional): Matplotlib Axes object to plot on. If None, a new figure and axes are created. **kwargs: Additional keyword arguments passed to matplotlib's plot function. Returns: tuple[Figure, Axes]: The matplotlib Figure and Axes objects containing the plot. """ # calculate test information by summing item information across items - thetas = np.linspace(range[0], range[1], 100) + thetas = np.linspace(range[0], range[1], 100, dtype=float) information_array = np.zeros_like(thetas, dtype=float) + item_information_function_vec = np.vectorize(item_information_function) for item in items: - information_array += item_information_function( - mu=np.array(thetas).T, - a=np.array(item.a), - b=np.array(item.b), - c=np.array(item.c), - d=np.array(item.d), + information_array += item_information_function_vec( + np.array(thetas).T, + item=item, + model=model ) # setup figure @@ -277,14 +283,14 @@ def plot_theta_estimation_trace(simulation_id: str, true_abilities = np.array([ result.true_ability_level for result in test_results - ]) + ], dtype=float) estimations = np.array([ result.ability_estimation for result in test_results - ]) + ], dtype=float) - steps = np.array(range(len(test_results))) + steps = np.array(range(len(test_results)), dtype=float) # setup figure fig: Figure | SubFigure @@ -295,6 +301,8 @@ def plot_theta_estimation_trace(simulation_id: str, ax.plot(steps, true_abilities, label="True ability", color="black") ax.plot(steps, estimations, label="Ability Estimations", color="blue") + ax.set_xlabel("Step") + ax.set_ylabel("Ability level") ax.legend() return fig, ax diff --git a/docs/Content_Balancing.md b/docs/Content_Balancing.md new file mode 100644 index 0000000..58e5eca --- /dev/null +++ b/docs/Content_Balancing.md @@ -0,0 +1,126 @@ +# Content Balancing +This package currently supports two methods for Content Balancing: +- Maximum Priority Index (Cheng & Chang, 2009) +- Weighted Penalty Model (Shin et al., 2009) + +## Maximum Priority Index +n MPI, items are assigned to groups. These groups, in turn, belong to constraints. +These constraints are implemented in the package as follows: +- Constraint name (important for the correct assignment of items) +- Weight +- Prevalence (Frequency / Relative Frequency of a constraint and its items) +For more background information, please refer to Cheng & Chang (2009). + +### Setup Item Pool +It is important to note that each item in the item pool +must be assigned to one or more content categories. +These specify which constraints the item is relevant to. +Therefore of course, an item can belong to multiple constraints. + +````python +import adaptivetesting as adt +import pandas as pd + +items = pd.DataFrame({ + "a": [1.32, 1.07, 0.84], + "b": [-0.63, 0.18, -0.84], + "c": [0.17, 0.10, 0.19], + "d": [0.87, 0.93, 1], + "content_categories": ["Math", "English", "Math"], + "id": [1, 2, 3] + }) +```` +In this example, we have two items belonging to the content category `Math` and one +to `English`. + +### Setup Adaptive Test +The adaptive test can, in general, be set up as usual. +But some additional properties, i.e. the constraints, have to be defined. +For simplicity, we will define all the arguments required for Content Balancing +prior to the test object. +```python +cb_args: adt.ContentBalancingArgs = { + "constraints": [ + adt.Constraint("Math", weight=0.5, prevalence=0.5), + adt.Constraint("English", weight=0.5, prevalence=0.5) + ] + } +``` +In this example, we set the prevalence and the weight of both constraints to `0.5`. +The test can then be assembled. +```python +adaptive_test = adt.TestAssembler( + item_pool=item_pool, + simulation_id="1", + participant_id="2", + ability_estimator=adt.MLEstimator, + content_balancing="MaximumPriorityIndex", + content_balancing_args=cb_args + ) +``` + +## Weighted Penalty Model +The WPM itself follows a very complex ruleset. +For more background on the operation of the WPM, see Shin et al. (2009). + +To implement the WPM in an adaptive test, constraints have to be defined. +These consist of the following properties: +- name +- weight +- prevalence (0 < x < 1) +- lower bound +- upper bound + +Again, we will define all the arguments required for Content Balancing +before the actual test object. +```python +cb_args: adt.ContentBalancingArgs = { + "constraints": [ + adt.Constraint( + "Math", + weight=0.5, + prevalence=0.2, + lower=0, + upper=1 + ), + adt.Constraint( + "English", + weight=0.5, + prevalence=0.2, + lower=0, + upper=1 + ) + ], + "constraint_weight": 0.5, + "information_weight": 0.5 +} +``` +WEP also requires to weight the constraints and item information. +In this example, the weights are fixed but can also be set to functions so that +the weights may be adapted during the testing procedure. +For that, `"constraint_weight"` and/or `"information_weight"` must be set to +functions that take an instance of the adaptive test as argument +and return a float (`Callable[[AdaptiveTest], float]`). + +Finally, the adaptive test can be specified as usual. +```python +adaptive_test = adt.TestAssembler( + item_pool=item_pool, + simulation_id="1", + participant_id="12", + ability_estimator=adt.MLEstimator, + content_balancing="WeightedPenaltyModel", + content_balancing_args=cb_args + ) +``` + +## References +Cheng, Y., & Chang, H. (2009). The maximum priority index method for severely constrained item selection +in computerized adaptive testing. +British Journal of Mathematical and Statistical Psychology, 62(2), 369–383. +https://doi.org/10.1348/000711008X304376 + +Shin, C. D., Chien, Y., Way, W. D., & Swanson, L. (2009, April). Weighted Penalty +Model for Content Balancing in CATS. +https://www.pearsonassessments.com/content/dam/school/global/clinical/us/ +assets/testnav/weighted-penalty-model.pdf \ No newline at end of file diff --git a/docs/Exposure_Control.md b/docs/Exposure_Control.md new file mode 100644 index 0000000..2e12b60 --- /dev/null +++ b/docs/Exposure_Control.md @@ -0,0 +1,103 @@ +# Exposure Control + +This package currently supports two methods for Exposure Control: +- Randomesque Item Selection (Kingsbury & Zara, 1989, 1991) +- Maximum Priority Index (Cheng & Chang, 2009) + +## Randomesque +Randomesque item selection does not select the *most* informative item, +instead a random draw is made from the $n$ most informative items. +This can be easily set up in the `TestAssembler` by specifying +the `exposure_control` argument. +`exposure_control_args` takes a dictionary in which we can define the number +items and, if required, a seed for the random draw. + +```python +import adaptivetesting as adt + +test = adt.TestAssembler( + ..., + exposure_control="Randomesque", + exposure_control_args={ + "n_items": 4, + "seed": None + } +) +``` +The final test can then be used and run as usual. + +## Maximum Priority Index +In MPI, items are assigned to groups. These groups, in turn, belong to constraints. +These constraints are implemented in the package as follows: +- Constraint name (important for the correct assignment of items) +- Weight +- Prevalence (Frequency / Relative Frequency of a constraint and its items) +For more background information, please refer to Cheng & Chang (2009). + +### Setup Item Pool +It is important to note that each item in the item pool +must be assigned to one or more content categories. +These specify which constraints the item is relevant to. +Therefore of course, an item can belong to multiple constraints. + +````python +import adaptivetesting as adt +import pandas as pd + +items = pd.DataFrame({ + "a": [1.32, 1.07, 0.84], + "b": [-0.63, 0.18, -0.84], + "c": [0.17, 0.10, 0.19], + "d": [0.87, 0.93, 1], + "content_categories": ["Math", "English", "Math"], + "id": [1, 2, 3] + }) +```` +In this example, we have two items belonging to the content category `Math` and one +to `English`. + +### Setup Adaptive Test +The adaptive test can, in general, be set up as usual. +But some additional properties, i.e. the constraints, have to be defined. +For simplicity, we will define all the arguments required for Exposure Control +prior to the test object. +```python +ex_args: adt.ExposureControlArgs = { + "constraints": [ + adt.Constraint("Math", weight=0.5, prevalence=0.5), + adt.Constraint("English", weight=0.5, prevalence=0.5) + ], + "participant_ids": ["1"], + "output_format": adt.ResultOutputFormat.CSV + } +``` +In this example, we set the prevalence and the weight of both constraints to `0.5`. +Additionally, we expect to have a single previous test results (from participant `"1"`) +saved in the CSV file format. + +The test can then be assembled. +```python +adaptive_test = adt.TestAssembler( + item_pool=item_pool, + simulation_id="1", + participant_id="2", + ability_estimator=adt.MLEstimator, + exposure_control="MaximumPriorityIndex", + exposure_control_args=ex_args, + debug=False + ) +``` + +## References + +Cheng, Y., & Chang, H. (2009). The maximum priority index method for severely constrained item selection +in computerized adaptive testing. +British Journal of Mathematical and Statistical Psychology, 62(2), 369–383. +https://doi.org/10.1348/000711008X304376 + +Kingsbury, G. G., & Zara, A. R. (1991). A Comparison of Procedures for Content-Sensitive +Item Selection in Computerized Adaptive Tests. Applied Measurement in Education, 4(3), 241–261. +Psychology and Behavioral Sciences Collection. https://doi.org/10.1207/s15324818ame0403_4 + +Kingsbury, G. G., & Zara, A. R. (1989). Procedures for selecting items for +computerized adaptive tests. Applied Measurement in Education, 2(4), 359–375. \ No newline at end of file diff --git a/docs/Getting_Started.md b/docs/Getting_Started.md new file mode 100644 index 0000000..302d861 --- /dev/null +++ b/docs/Getting_Started.md @@ -0,0 +1,69 @@ +# Getting Started + +This small tutorial will give a general introduction to the package, +show the installation and how a small simulation is performed. + +### 1. Package Installation + +The package can be installed through `pip` or `conda` - depending on the user's +preference. +```bash +pip install adaptivetesting +``` +or +```bash +conda install conda-forge::adaptivetesting +``` + +### 2. Load the items and set up the item pool +At first, the package should be imported. We recommend using a short alias, such as `adt`. +Then, the item pool can be loaded from a compatible format, such as a dictionary or simple lists. +In this example, we will load the item parameters from python lists. +```python +import adaptivetesting as adt +item_pool = adt.ItemPool.load_from_list( + a = [0.42, 0.3, 1.5], + b = [0.5, 0.9, 1.1] +) +``` +Here, we use a 2PL model which is a simplified version of the 4PL model so that +the `c` and `d` parameters are not manually set but inferred by the package. + +### 3. Define the adaptive test +The general adaptive testing procedure can be easily defined with the +`TestAssembler` class. This class supports numerous arguments to +also allow rather complex procedures. +For this example, we will only focus on a very basic configuration. + +We configure a test for a single participant using ML for the ability estimation +and MFI for the item selection. Because we want to simulate the test later, +we have to specify a true ability level (here `0`) so that the package +may draw corresponding response patterns. For reproducibility, we also +set a seed (`123`). + +```python +test = adt.TestAssembler( + item_pool = item_pool, + simulation_id="test", + participant_id="1", + ability_estimator=adt.MLEstimator, + true_ability_level=0, + seed=123 + ) + +``` + +### 4. Set up the simulation +The simulation can now simply be set up with the `Simulation` class. +Additionally, we have to specify a format in which the test results will be saved. +```python +simulation = adt.Simulation(test, adt.ResultOutputFormat.CSV) +``` + +### 5. Run the simulation +To start the actual simulation, we have to specify a stopping criterion. +We will use a standard error value of $0.4$ in this example. +```python +simulation.simulate(criterion=adt.StoppingCriterion.SE, value=0.4) +simulation.save_test_results() +``` \ No newline at end of file diff --git a/docs/Home.md b/docs/Home.md new file mode 100644 index 0000000..3ba968f --- /dev/null +++ b/docs/Home.md @@ -0,0 +1,41 @@ +# adaptivetesting +![Logo of the adaptivetesting package](_static/logo.svg) + +![Following SPEC 0](_static/spec0.svg) +![Supported Python Versions](_static/python.svg) +![Package Repositories: PyPi, conda-forge](_static/package.svg) + +## Features + +* **IRT Models** + * 4PL, 3PL, 2PL, Rasch + * GRM + * GPCM +* **Ability Estimators** + * Maximum Likelihood + * Bayes Modal + * Expected a Posteriori +* **Item Selection** + * MFI +* **Exposure Control** + * Randomesque + * Maximum Priority Index +* **Content Balancing** + * Maximum Priority Index + * Weighted Penalty Model + * **Stopping Criterion** + * Standard Error + * Test Length + + +## Package Installation +### PyPi + +```bash +pip install adaptivetesting +``` + +### Conda +```bash +conda install conda-forge::adaptivetesting +``` \ No newline at end of file diff --git a/docs/Simulation.md b/docs/Simulation.md new file mode 100644 index 0000000..a59b287 --- /dev/null +++ b/docs/Simulation.md @@ -0,0 +1,72 @@ +# Simulation + +## Single Simulation + +For simulating an adaptive test, first the item pool has to be initialized. +```python +import adaptivetesting as adt +item_pool = adt.ItemPool.load_from_list( + a = [0.42, 0.3, 1.5], + b = [0.5, 0.9, 1.1] +) +``` +Then, the test object can be created using the `TestAssembler` class. For reproducibility, a seed can be set. +```python +test = adt.TestAssembler( + item_pool = item_pool, + simulation_id="test", + participant_id="1", + ability_estimator=adt.MLEstimator, + true_ability_level=0, + seed=123 +) +``` + +The simulation itself is set up with the `Simulation` class which specifies the output format for +the test results and the stopping criteria. +```python +simulation = adt.Simulation(test, adt.ResultOutputFormat.CSV) + +simulation.simulate(criterion=adt.StoppingCriterion.SE, value=0.4) +simulation.save_test_results() +``` + +## Simulation Pool +For large scale simulations, the `SimulationPool` class can be used. +For every single simulation, a test object has to be created which needs to be saved in a list. +```python +tests = [ + adt.TestAssembler( + item_pool=item_pool, + simulation_id="example", + participant_id="1", + ability_estimator=adt.MLEstimator, + item_selector=adt.maximum_information_criterion, + true_ability_level=0, + seed=123 + ), + adt.TestAssembler( + item_pool=item_pool, + simulation_id="example", + participant_id="2", + ability_estimator=adt.MLEstimator, + item_selector=adt.maximum_information_criterion, + true_ability_level=1, + seed=123 + ), +] +``` +The simulation pool allows the tests to run sequentially without additional setup but also in parallel. +```python +sim_pool = adt.SimulationPool( + adaptive_tests=tests, + test_result_output=adt.ResultOutputFormat.CSV, + criterion=adt.StoppingCriterion.SE, + value=0.4 +) +sim_pool.start() +``` +Depending on the operating system, the simulation pool uses either multithreading (on Windows) +or multiprocessing (on other platforms) to run the simulation for each adaptive test. +Note that parallel processing is not supported for the use in jupyter notebooks. +For that, `parallel` has to be set to `False`. \ No newline at end of file diff --git a/docs/Testing_Software.md b/docs/Testing_Software.md new file mode 100644 index 0000000..f1d47bb --- /dev/null +++ b/docs/Testing_Software.md @@ -0,0 +1,61 @@ +# Testing Software +With `adaptivetesting`, users can simulate adaptive tests +but also collect real data. +For data collection, a function has to be defined +which allows interaction with the examinees. +This can be via testing software such as PsychoPy or any +other appropriate interface. + +In this example, we will just collect responses from the commandline. +In real-world data collection, items selected from the test can be used to match the appropriate stimuli +which are then displayed to the participants. +```python +import adaptivetesting as adt + +def get_response (item : adt.TestItem) -> int: + print(f"Selected item: {item.id}") + response = input("Response >") + return int(response) +``` + +Then, we can set up the adaptive test object. +```python +adaptive_test = adt.TestAssembler ( + item_pool=item_pool, + simulation_id="example_data_collection", + participant_id="dummy", + ability_estimator=adt.MLEstimator, + item_selector=adt.maximum_information_criterion, + simulation=False + ) +``` +It is important that the `simulation` parameter is set to `False` so that the package +does not simulate responses but expects real user input. +To enable data collection, the `get_response` method of the +test object has to be overridden. +```python +adaptive_test.get_response = get_response +``` + +Simple additional code is required to let the test run until a stopping criterion is met +and the test results may be saved. +```python +# start adaptive test +while True: + adaptive_test.run_test_once() + + # check stopping criterion + if adaptive_test.standard_error <= 0.4: + break + + # end test if all items have been shown + if len(adaptive_test.item_pool.test_items) == 0: + break + +data_context = adt.CSVContext( + adaptive_test.simulation_id, + adaptive_test.participant_id +) + +data_context.save(adaptive_test.test_results) +``` \ No newline at end of file diff --git a/docs/_Sidebar.md b/docs/_Sidebar.md new file mode 100644 index 0000000..607706d --- /dev/null +++ b/docs/_Sidebar.md @@ -0,0 +1,18 @@ +### [Home](Home) + + +**Tutorials** +- [Getting Started](Getting_Started) +- [Exposure Control](Exposure_Control) +- [Content Balancing](Content_Balancing) +- [Testing Software](Testing_Software) +- [Simulation](Simulation) + +**API Reference** +- [data module](API-data) +- [implementations module](API-implementations) +- [math module](API-math) +- [models module](API-models) +- [services module](API-services) +- [simulation module](API-simulation) +- [utils module](API-utils) \ No newline at end of file diff --git a/docs/_static/create_badges.js b/docs/_static/create_badges.js new file mode 100644 index 0000000..b8adfd4 --- /dev/null +++ b/docs/_static/create_badges.js @@ -0,0 +1,51 @@ +const { makeBadge } = require("badge-maker"); +const fs = require("node:fs"); + +function SPEC0() { + const format = { + label: 'SPEC', // (Optional) Badge label + message: '0', // (Required) Badge message + labelColor: '#555', // (Optional) Label color + color: '#4c1', // (Optional) Message color + } + const badgeString = makeBadge(format); + fs.writeFile("spec0.svg", badgeString, e => { + if (e != null) { + console.log(e) + } + }); +} + +function PythonVersion() { + const format = { + label: 'Python', // (Optional) Badge label + message: '3.12 | 3.13 | 3.14', // (Required) Badge message + labelColor: '#555', // (Optional) Label color + color: 'rgb(17, 86, 204)', // (Optional) Message color + } + const badgeString = makeBadge(format); + fs.writeFile("python.svg", badgeString, e => { + if (e != null) { + console.log(e) + } + }); +} + +function PackageManager(){ + const format = { + label: "Package Repositories", + message: "PyPI | conda-forge", + labelColor: "#555", + color: "rgb(17, 86, 204)" + } + const badgeString = makeBadge(format); + fs.writeFile("package.svg", badgeString, e => { + if(e != null){ + console.log(e) + } + }) +} + +SPEC0() +PythonVersion() +PackageManager(); \ No newline at end of file diff --git a/docs/source/_static/logo.svg b/docs/_static/logo.svg similarity index 100% rename from docs/source/_static/logo.svg rename to docs/_static/logo.svg diff --git a/docs/_static/package-lock.json b/docs/_static/package-lock.json new file mode 100644 index 0000000..55d7d7f --- /dev/null +++ b/docs/_static/package-lock.json @@ -0,0 +1,92 @@ +{ + "name": "icons", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "icons", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "anafanafo": "^2.0.0", + "badge-maker": "^5.0.2", + "binary-search": "^1.3.6", + "char-width-table-consumer": "^1.0.0", + "color-convert": "^0.5.3", + "color-name": "^1.1.4", + "css-color-converter": "^2.0.0", + "css-unit-converter": "^1.1.2" + }, + "devDependencies": {} + }, + "node_modules/anafanafo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anafanafo/-/anafanafo-2.0.0.tgz", + "integrity": "sha512-Nlfq7NC4AOkTJerWRIZcOAiMNtIDVIGWGvQ98O7Jl6Kr2Dk0dX5u4MqN778kSRTy5KRqchpLdF2RtLFEz9FVkQ==", + "license": "MIT", + "dependencies": { + "char-width-table-consumer": "^1.0.0" + } + }, + "node_modules/badge-maker": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/badge-maker/-/badge-maker-5.0.2.tgz", + "integrity": "sha512-Xd3YUmKPEShQcn6PFB03Wxq0RNJRFwVVroyRz0qIjSXwniYUGsGWNHqtNsQYi/Sbs8Ni7qAEf7LKgDOtcAoCDg==", + "license": "CC0-1.0", + "dependencies": { + "anafanafo": "2.0.0", + "css-color-converter": "^2.0.0" + }, + "bin": { + "badge": "lib/badge-cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/binary-search": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz", + "integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==", + "license": "CC0-1.0" + }, + "node_modules/char-width-table-consumer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/char-width-table-consumer/-/char-width-table-consumer-1.0.0.tgz", + "integrity": "sha512-Fz4UD0LBpxPgL9i29CJ5O4KANwaMnX/OhhbxzvNa332h+9+nRKyeuLw4wA51lt/ex67+/AdsoBQJF3kgX2feYQ==", + "license": "MIT", + "dependencies": { + "binary-search": "^1.3.5" + } + }, + "node_modules/color-convert": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "integrity": "sha512-RwBeO/B/vZR3dfKL1ye/vx8MHZ40ugzpyfeVG5GsiuGnrlMWe2o8wxBbLCpw9CsxV+wHuzYlCiWnybrIA0ling==" + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/css-color-converter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-color-converter/-/css-color-converter-2.0.0.tgz", + "integrity": "sha512-oLIG2soZz3wcC3aAl/7Us5RS8Hvvc6I8G8LniF/qfMmrm7fIKQ8RIDDRZeKyGL2SrWfNqYspuLShbnjBMVWm8g==", + "license": "MIT", + "dependencies": { + "color-convert": "^0.5.2", + "color-name": "^1.1.4", + "css-unit-converter": "^1.1.2" + } + }, + "node_modules/css-unit-converter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", + "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==", + "license": "MIT" + } + } +} diff --git a/docs/_static/package.json b/docs/_static/package.json new file mode 100644 index 0000000..2bb20dd --- /dev/null +++ b/docs/_static/package.json @@ -0,0 +1,22 @@ +{ + "name": "icons", + "version": "1.0.0", + "description": "", + "license": "ISC", + "author": "", + "type": "commonjs", + "main": "create_badges.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "anafanafo": "^2.0.0", + "badge-maker": "^5.0.2", + "binary-search": "^1.3.6", + "char-width-table-consumer": "^1.0.0", + "color-convert": "^0.5.3", + "color-name": "^1.1.4", + "css-color-converter": "^2.0.0", + "css-unit-converter": "^1.1.2" + } +} diff --git a/docs/_static/package.svg b/docs/_static/package.svg new file mode 100644 index 0000000..0c6540c --- /dev/null +++ b/docs/_static/package.svg @@ -0,0 +1 @@ +Package Repositories: PyPI | conda-forgePackage RepositoriesPyPI | conda-forge \ No newline at end of file diff --git a/docs/_static/python.svg b/docs/_static/python.svg new file mode 100644 index 0000000..19c79aa --- /dev/null +++ b/docs/_static/python.svg @@ -0,0 +1 @@ +Python: 3.12 | 3.13 | 3.14Python3.12 | 3.13 | 3.14 \ No newline at end of file diff --git a/docs/_static/spec0.svg b/docs/_static/spec0.svg new file mode 100644 index 0000000..e6cb613 --- /dev/null +++ b/docs/_static/spec0.svg @@ -0,0 +1 @@ +SPEC: 0SPEC0 \ No newline at end of file diff --git a/docs/data.md b/docs/data.md deleted file mode 100644 index 918d11e..0000000 --- a/docs/data.md +++ /dev/null @@ -1,69 +0,0 @@ -# data Module - -## PickleContext - -### *class* adaptivetesting.data.PickleContext(simulation_id: str, participant_id: int) - -Bases: [`ITestResults`](services.md#adaptivetesting.services.ITestResults) - -Implementation of the ITestResults interface for -saving test results to the pickle format. -The resulting pickle file .pickle -will be of the standard pickle format which depends -on the used python version. - -Args: -: simulation_id (str): Not used but required by the interface -
- participant_id (int): participant id and table name - -#### load() → List[[TestResult](models.md#adaptivetesting.models.TestResult)] - -Loads results from the database. -The implementation of this method is required -by the interface. However, is does not have -any implemented functionality and will throw an error -if used. - -Returns: List[TestResult] - -#### save(test_results: List[[TestResult](models.md#adaptivetesting.models.TestResult)]) → None - -Saves a list of test results to a pickle binary file -(.pickle). - -Args: -: test_results (List[TestResult]): list of test results - -## SQLiteContext - -### *class* adaptivetesting.data.SQLiteContext(simulation_id: str, participant_id: int) - -Bases: [`ITestResults`](services.md#adaptivetesting.services.ITestResults) - -Implementation of the ITestResults interface for -saving test results to a SQLITE database. -The resulting sqlite file .db -will be of the SQLITE3 format. - -Args: -: simulation_id (str): db filename -
- participant_id (int): participant id and table name - -#### load() → List[[TestResult](models.md#adaptivetesting.models.TestResult)] - -Loads results from the database. -The implementation of this method is required -by the interface. However, is does not have -any implemented functionality and will throw an error. - -Returns: List[TestResult] - -#### save(test_results: List[[TestResult](models.md#adaptivetesting.models.TestResult)]) → None - -Saves a list of test results to the database -in the table . - -Args: -: test_results (List[TestResult]): list of test results diff --git a/docs/Makefile b/docs/docs_source/Makefile similarity index 100% rename from docs/Makefile rename to docs/docs_source/Makefile diff --git a/docs/make.bat b/docs/docs_source/make.bat similarity index 100% rename from docs/make.bat rename to docs/docs_source/make.bat diff --git a/docs/requirements.txt b/docs/docs_source/requirements.txt similarity index 100% rename from docs/requirements.txt rename to docs/docs_source/requirements.txt diff --git a/docs/source/data.rst b/docs/docs_source/source/API-data.rst similarity index 100% rename from docs/source/data.rst rename to docs/docs_source/source/API-data.rst diff --git a/docs/source/implementations.rst b/docs/docs_source/source/API-implementations.rst similarity index 100% rename from docs/source/implementations.rst rename to docs/docs_source/source/API-implementations.rst diff --git a/docs/source/math.rst b/docs/docs_source/source/API-math.rst similarity index 100% rename from docs/source/math.rst rename to docs/docs_source/source/API-math.rst diff --git a/docs/source/models.rst b/docs/docs_source/source/API-models.rst similarity index 100% rename from docs/source/models.rst rename to docs/docs_source/source/API-models.rst diff --git a/docs/source/services.rst b/docs/docs_source/source/API-services.rst similarity index 100% rename from docs/source/services.rst rename to docs/docs_source/source/API-services.rst diff --git a/docs/source/simulation.rst b/docs/docs_source/source/API-simulation.rst similarity index 100% rename from docs/source/simulation.rst rename to docs/docs_source/source/API-simulation.rst diff --git a/docs/source/tests.rst b/docs/docs_source/source/API-tests.rst similarity index 100% rename from docs/source/tests.rst rename to docs/docs_source/source/API-tests.rst diff --git a/docs/docs_source/source/API-utils.rst b/docs/docs_source/source/API-utils.rst new file mode 100644 index 0000000..f3a1f90 --- /dev/null +++ b/docs/docs_source/source/API-utils.rst @@ -0,0 +1,9 @@ +utils Module +================= + + +.. automodule:: adaptivetesting.data + :members: + :undoc-members: + :show-inheritance: + :imported-members: diff --git a/docs/source/conf.py b/docs/docs_source/source/conf.py similarity index 70% rename from docs/source/conf.py rename to docs/docs_source/source/conf.py index e054868..fd87166 100644 --- a/docs/source/conf.py +++ b/docs/docs_source/source/conf.py @@ -1,7 +1,7 @@ import os import sys from sphinx.application import Sphinx -sys.path.insert(0, os.path.abspath('../')) +sys.path.insert(0, os.path.abspath('../../')) # Configuration file for the Sphinx documentation builder. # @@ -12,9 +12,6 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = 'adaptivetesting' -copyright = '2025, Jonas Engicht' -author = 'Jonas Engicht' -release = '2025' # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration @@ -31,19 +28,4 @@ html_theme = 'sphinx_book_theme' html_static_path = ['_static'] -html_css_files = [ - 'main.css', -] -html_logo = "_static/logo.svg" -html_theme_options = { - "navigation_depth": -1, - "repository_url": "https://github.com/condecon/adaptivetesting", - "use_issues_button": True - -} - - - - -def setup(app: Sphinx): - app.add_css_file("main.css") +markdown_uri_doc_suffix = "" \ No newline at end of file diff --git a/docs/docs_source/source/index.rst b/docs/docs_source/source/index.rst new file mode 100644 index 0000000..3d5732c --- /dev/null +++ b/docs/docs_source/source/index.rst @@ -0,0 +1,15 @@ +API +======== + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + + API-data + API-implementations + API-math + API-models + API-simulation + API-services + API-utils + API-tests \ No newline at end of file diff --git a/docs/implementations.md b/docs/implementations.md deleted file mode 100644 index c625d6e..0000000 --- a/docs/implementations.md +++ /dev/null @@ -1,117 +0,0 @@ -# implementations Module - -## DefaultImplementation - -### *class* adaptivetesting.implementations.DefaultImplementation(item_pool: [ItemPool](models.md#adaptivetesting.models.ItemPool), simulation_id: str, participant_id: int, true_ability_level: float, initial_ability_level: float = 0, simulation=True, debug=False) - -Bases: [`AdaptiveTest`](models.md#adaptivetesting.models.AdaptiveTest) - -This class represents the Default implementation using -Maximum Likelihood Estimation and Urry’s rule during the test. - -Args: -: item_pool (ItemPool): item pool used for the test -
- simulation_id (str): simulation id -
- participant_id (int): participant id -
- true_ability_level (float): true ability level (must always be set) -
- initial_ability_level (float): initially assumed ability level -
- simulation (bool): will the test be simulated -
- debug (bool): enables debug mode - -#### estimate_ability_level() → float - -Estimates latent ability level using ML. -If responses are only 1 or 0, -the ability will be set to one -of the boundaries of the estimation interval ([-10,10]). - -Returns: -: float: ability estimation - -## PreTest - -### *class* adaptivetesting.implementations.PreTest(items: List[[TestItem](models.md#adaptivetesting.models.TestItem)], seed: int | None = None) - -Bases: `object` - -The pretest class can be used to draw items randomly from -difficulty quantiles -of the item pool. - -Args: -: items: Item pool -
- seed (int): A seed for the item selection can be provided. - : If not, the item selection will be drawn randomly, and you will not be able - to reproduce the results. - -#### calculate_quantiles() → Array - -Calculates quantiles 0.25, 0.5, 0.75 - -#### select_item_in_interval(lower: float, upper: float) → [TestItem](models.md#adaptivetesting.models.TestItem) - -Draws item from a pool in the specified interval. -The item difficulty is > than the lower limit and <= the higher limit. - -Args: -: lower (float): Lower bound of the item difficulty interval. -
- upper (float): Upper bound of the item difficulty interval. - -Returns: -: TestItem: Selected item. - -#### select_random_item_quantile() → List[[TestItem](models.md#adaptivetesting.models.TestItem)] - -Selects a random item from the 0.25, 0.5 and 0.75 quantiles. - -Returns: -: List[TestItem]: Selected item. - -## SemiAdaptiveImplementation - -### *class* adaptivetesting.implementations.SemiAdaptiveImplementation(item_pool: [ItemPool](models.md#adaptivetesting.models.ItemPool), simulation_id: str, participant_id: int, true_ability_level: float, initial_ability_level: float = 0, simulation=True, debug=False, pretest_seed=12345) - -Bases: [`AdaptiveTest`](models.md#adaptivetesting.models.AdaptiveTest) - -This class represents the Semi-Adaptive implementation using -Maximum Likelihood Estimation and Urry’s rule during the test. -The pretest is 4 items long. - -Args: -: item_pool (ItemPool): item pool used for the test -
- simulation_id (str): simulation id -
- participant_id (int): participant id -
- true_ability_level (float): true ability level (must always be set) -
- initial_ability_level (float): initially assumed ability level -
- simulation (bool): will the test be simulated -
- debug (bool): enables debug mode -
- pretest_seed (int): seed used for the random number generator to draw pretest items. - -#### estimate_ability_level() → float - -Estimates latent ability level using ML. -If responses are only 1 or 0, -the ability will be set to one -of the boundaries of the estimation interval ([-10,10]). - -Returns: -: float: ability estimation - -#### pre_test() - -Runs pretest diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 61fa3e8..0000000 --- a/docs/index.md +++ /dev/null @@ -1,32 +0,0 @@ -# adaptivetesting - -*adaptivetesting* is a Python package for computer-aided adaptive -testing that can be used to simulate and implement custom adaptive tests -in real-world testing scenarios. - -# Getting Started - ---- - -Required Python version: >= 3.11 (other versions may work, but they are not officially supported) - -```bash -pip install adaptivetesting -``` - -If you want to install the current development version, -you can do so by running the following command: - -```bash -pip install git+https://github.com/condecon/adaptivetesting -``` - -# Contents: - -* [data Module](data.md) -* [implementations Module](implementations.md) -* [math Module](math.md) -* [models Module](models.md) -* [simulation Module](simulation.md) -* [services Module](services.md) -* [tests Module](tests.md) diff --git a/docs/math.md b/docs/math.md deleted file mode 100644 index f224155..0000000 --- a/docs/math.md +++ /dev/null @@ -1,254 +0,0 @@ -# math Module - -## Estimators - -### MLEstimator - -### *class* adaptivetesting.math.estimators.MLEstimator(response_pattern: List[int] | Array, items: List[[TestItem](models.md#adaptivetesting.models.TestItem)], optimization_interval: Tuple[float, float] = (-10, 10)) - -Bases: [`IEstimator`](services.md#adaptivetesting.services.IEstimator) - -This class can be used to estimate the current ability level -of a respondent given the response pattern and the corresponding -item parameters. -The estimation uses Maximum Likelihood Estimation. - -Args: -: response_pattern (List[int]): list of response patterns (0: wrong, 1:right) -
- items (List[TestItem]): list of answered items - -#### get_estimation() → float - -Estimate the current ability level by searching -for the maximum of the likelihood function. -A line-search algorithm is used. - -Returns: -: float: ability estimation - -### Prior - -### *class* adaptivetesting.math.estimators.Prior - -Bases: `ABC` - -Base class for prior distributions - -#### *abstractmethod* pdf(x: float | Array) → Array - -Probability density function for a prior distribution - -Args: -: x (float | np.ndarray): point at which to calculate the function value - -Returns: -: ndarray: function value - -### NormalPrior - -### *class* adaptivetesting.math.estimators.NormalPrior(mean: float, sd: float) - -Bases: [`Prior`](#adaptivetesting.math.estimators.Prior) - -Normal distribution as prior for Bayes Modal estimation - -Args: -: mean (float): mean of the distribution -
- sd (float): standard deviation of the distribution - -#### pdf(x: float | Array) → Array - -Probability density function for a prior distribution - -Args: -: x (float | np.ndarray): point at which to calculate the function value - -Returns: -: ndarray: function value - -### probability_y1 - -### adaptivetesting.math.estimators.probability_y1(mu: Array, a: Array, b: Array, c: Array, d: Array) → Array - -Probability of getting the item correct given the ability level. - -Args: -: mu (jnp.ndarray): latent ability level -
- a (jnp.ndarray): item discrimination parameter -
- b (jnp.ndarray): item difficulty parameter -
- c (jnp.ndarray): pseudo guessing parameter -
- d (jnp.ndarray): inattention parameter - -Returns: -: jnp.ndarray: probability of getting the item correct - -### probability_y0 - -### adaptivetesting.math.estimators.probability_y0(mu: Array, a: Array, b: Array, c: Array, d: Array) → Array - -Probability of getting the item wrong given the ability level. - -Args: -: mu (jnp.ndarray): latent ability level -
- a (jnp.ndarray): item discrimination parameter -
- b (jnp.ndarray): item difficulty parameter -
- c (jnp.ndarray): pseudo guessing parameter -
- d (jnp.ndarray): inattention parameter - -Returns: -: jnp.ndarray: probability of getting the item wrong - -### maximize_likelihood_function - -### adaptivetesting.math.estimators.maximize_likelihood_function(a: Array, b: Array, c: Array, d: Array, response_pattern: Array, border: tuple[float, float] = (-10, 10)) → float - -Find the ability value that maximizes the likelihood function. -This function uses the minimize_scalar function from scipy and the “bounded” method. - -Args: -: a (jnp.ndarray): item discrimination parameter -
- b (jnp.ndarray): item difficulty parameter -
- c (jnp.ndarray): pseudo guessing parameter -
- d (jnp.ndarray): inattention parameter -
- response_pattern (jnp.ndarray): response pattern of the item - border (tuple[float, float], optional): border of the optimization interval. - Defaults to (-10, 10). - -Raises: -: AlgorithmException: if the optimization fails or the response - pattern consists of only one type of response. - -Returns: -: float: optimized ability value - -### likelihood - -### adaptivetesting.math.estimators.likelihood(mu: Array, a: Array, b: Array, c: Array, d: Array, response_pattern: Array) → Array - -Likelihood function of the 4-PL model. -For optimization purposes, the function returns the negative value of the likelihood function. -To get the *real* value, multiply the result by -1. - -Args: -: mu (jnp.ndarray): ability level -
- a (jnp.ndarray): item discrimination parameter -
- b (jnp.ndarray): item difficulty parameter -
- c (jnp.ndarray): pseudo guessing parameter -
- d (jnp.ndarray): inattention parameter - -Returns: -: float: likelihood value of given ability value - -### maximize_posterior - -### adaptivetesting.math.estimators.maximize_posterior(a: Array, b: Array, c: Array, d: Array, response_pattern: Array, prior: [Prior](#adaptivetesting.math.estimators.Prior)) → float - -\_summary_ - -Args: -: a (np.ndarray): \_description_ -
- b (np.ndarray): \_description_ -
- c (np.ndarray): \_description_ -
- d (np.ndarray): \_description_ -
- response_pattern (np.ndarray): \_description_ -
- prior (Prior): \_description_ - -Returns: -: float: Bayes Modal estimator for the given parameters - -## Item Selection - -### urrys_rule - -### adaptivetesting.math.item_selection.urrys_rule(items: List[[TestItem](models.md#adaptivetesting.models.TestItem)], ability: float) → [TestItem](models.md#adaptivetesting.models.TestItem) - -Urry’s rule selects the test item -which has the minimal difference between -the item’s difficulty and the ability level. - -Args: -: items (List[TestItem]): Test items (item pool) -
- ability (float): Ability level (current ability estimation) - -Returns: -: TestItem: selected test item - -## standard_error - -### adaptivetesting.math.standard_error(answered_items: List[[TestItem](models.md#adaptivetesting.models.TestItem)], estimated_ability_level: float, estimator: Literal['ML', 'BM'] = 'ML', sd: float | None = None) → float - -Calculates the standard error using the test information function. -If Bayes Modal is used for the ability estimation, a standard deviation value -of the prior distribution has to be provided. - -Args: -: answered_items (List[float]): List of answered items -
- estimated_ability_level (float): Currently estimated ability level -
- estimator (Literal[“ML”, “BM”]): Ability estimator (Default: ML) -
- sd (float | None): Standard deviation of the prior distribution. Only required for BM. - -Raises: -: ValueError - -Returns: -: float: Standard error - -## test_information_function - -### adaptivetesting.math.test_information_function(mu: Array, a: Array, b: Array, c: Array, d: Array) → float - -Calculates test information. - -Args: -: mu (np.ndarray): ability level - a (np.ndarray): discrimination parameter - b (np.ndarray): difficulty parameter - c (np.ndarray): guessing parameter - d (np.ndarray): slipping parameter - -Returns: -: float: test information - -## Utilities - -### generate_response_pattern - -### adaptivetesting.math.generate_response_pattern(ability: float, items: list[[TestItem](models.md#adaptivetesting.models.TestItem)], seed: int | None = None) → list[int] - -Generates a response pattern for a given ability level -and item difficulties. Also, a seed can be set. - -Args: -: ability (float): participants ability - items (list[TestItem]): test items - seed (int, optional): Seed for the random process. - -Returns: -: list[int]: response pattern diff --git a/docs/models.md b/docs/models.md deleted file mode 100644 index 7150fbc..0000000 --- a/docs/models.md +++ /dev/null @@ -1,248 +0,0 @@ -# models Module - -## AdaptiveTest - -### *class* adaptivetesting.models.AdaptiveTest(item_pool: [ItemPool](#adaptivetesting.models.ItemPool), simulation_id: str, participant_id: int, true_ability_level: float, initial_ability_level: float = 0, simulation: bool = True, DEBUG=False) - -Bases: `ABC` - -Abstract implementation of an adaptive test. -All abstract methods have to be overridden -to create an instance of this class. - -Abstract methods: -: - estimate_ability_level - -Args: -: item_pool (ItemPool): item pool used for the test -
- simulation_id (str): simulation id -
- participant_id (int): participant id -
- true_ability_level (float): true ability level (must always be set) -
- initial_ability_level (float): initially assumed ability level -
- simulation (bool): will the test be simulated -
- DEBUG (bool): enables debug mode - -#### check_length_criterion(value: float) → bool - -#### check_se_criterion(value: float) → bool - -#### *abstractmethod* estimate_ability_level() → float - -Estimates ability level. -The method has to be implemented by subclasses. - -Returns: -: float: estimated ability level - -#### get_ability_se() → float - -Calculate the current standard error -of the ability estimation. - -Returns: -: float: standard error of the ability estimation - -#### get_answered_items() → List[[TestItem](#adaptivetesting.models.TestItem)] - -Returns: -: List[TestItem]: answered items - -#### get_answered_items_difficulties() → List[float] - -Returns: -: List[float]: difficulties of answered items - -#### get_item_difficulties() → List[float] - -Returns: -: List[float]: difficulties of items in the item pool - -#### get_next_item() → [TestItem](#adaptivetesting.models.TestItem) - -Select next item using Urry’s rule. - -Returns: -: TestItem: selected item - -#### get_response(item: [TestItem](#adaptivetesting.models.TestItem)) → int - -If the adaptive test is not used for simulation. -This method is used to get user feedback. - -Args: -: item (TestItem): test item shown to the participant - -Return: -: int: participant’s response - -#### run_test_once() - -Runs the test procedure once. -Saves the result to test_results of -the current instance. - -## AlgorithmException - -### *class* adaptivetesting.models.AlgorithmException - -Bases: `Exception` - -Exception that is thrown when the estimation process did not find a maximum. - -## ItemPool - -### *class* adaptivetesting.models.ItemPool(test_items: List[[TestItem](#adaptivetesting.models.TestItem)], simulated_responses: List[int] | None = None) - -Bases: `object` - -An item pool has to be created for an adaptive test. -For that, a list of test items has to be provided. If the package is used -to simulate adaptive tests, simulated responses have to be supplied as well. -The responses are matched to the items internally. -Therefore, both have to be in the same order. - -Args: -: test_items (List[TestItem]): A list of test items. Necessary for any adaptive test. -
- simulated_responses (List[int]): A list of simulated responses. - Required for CAT simulations. - -#### delete_item(item: [TestItem](#adaptivetesting.models.TestItem)) → None - -Deletes item from item pool. -If simulated responses are defined, they will be deleted as well. - -Args: -: item (TestItem): The test item to delete. - -#### get_item_by_index(index: int) → Tuple[[TestItem](#adaptivetesting.models.TestItem), int] | [TestItem](#adaptivetesting.models.TestItem) - -Returns item and if defined the simulated response. - -Args: -: index (int): Index of the test item in the item pool to return. - -Returns: -: TestItem or (TestItem, Simulated Response) - -#### get_item_by_item(item: [TestItem](#adaptivetesting.models.TestItem)) → Tuple[[TestItem](#adaptivetesting.models.TestItem), int] | [TestItem](#adaptivetesting.models.TestItem) - -Returns item and if defined the simulated response. - -Args: -: item (TestItem): item to return. - -Returns: -: TestItem or (TestItem, Simulated Response) - -#### get_item_response(item: [TestItem](#adaptivetesting.models.TestItem)) → int - -Gets the simulated response to an item if available. -A ValueError will be raised if a simulated response is not available. - -Args: -: item (TestItem): item to get the corresponding response - -Returns: -: (int): response (either 0 or 1) - -#### *static* load_from_dataframe(source: DataFrame) → [ItemPool](#adaptivetesting.models.ItemPool) - -Creates item pool from a pandas DataFrame. -Required columns are: a, b, c, d. -Each column has to contain float values. -A simulated_responses (int values) column can be added to -the DataFrame to provide simulated responses. - -Args: -: source (DataFrame): \_description_ - -Returns: -: ItemPool: \_description_ - -#### *static* load_from_dict(source: dict[str, List[float]], simulated_responses: List[int] | None = None) → [ItemPool](#adaptivetesting.models.ItemPool) - -Creates test items from a dictionary. -The dictionary has to have the following keys: - -> - a -> - b -> - c -> - d - -each containing a list of float. - -Args: -: source (dict[str, List[float]]): item pool dictionary - -Returns: -: List[TestItem]: item pool - -#### *static* load_from_list(b: List[float], a: List[float] | None = None, c: List[float] | None = None, d: List[float] | None = None, simulated_responses: List[int] | None = None) → [ItemPool](#adaptivetesting.models.ItemPool) - -Creates test items from a list of floats. - -Args: -: a (List[float]): discrimination parameter -
- b (List[float]): difficulty parameter -
- c (List[float]): guessing parameter -
- d (List[float]): slipping parameter -
- simulated_responses (List[int]): simulated responses - -Returns: -: List[TestItem]: item pool - -## TestItem - -### *class* adaptivetesting.models.TestItem - -Bases: `object` - -Representation of a test item in the item pool. -The format is equal to the implementation in catR. - -Properties: -: - a (float): - - b (float): difficulty - - c (float): - - d (float): - -#### as_dict() → dict[str, float] - -## TestResult - -### *class* adaptivetesting.models.TestResult(test_id: str, ability_estimation: float, standard_error: float, showed_item: float, response: int, true_ability_level: float) - -Bases: `object` - -Representation of simulation test results - -#### ability_estimation *: float* - -#### *static* from_dict(dictionary: Dict) → [TestResult](#adaptivetesting.models.TestResult) - -Create a TestResult from a dictionary - -Args: -: dictionary: with the fields test_id, ability_estimation, standard_error, showed_item, response, - true_ability_level - -#### response *: int* - -#### showed_item *: float* - -#### standard_error *: float* - -#### test_id *: str* - -#### true_ability_level *: float* diff --git a/docs/readme.md b/docs/readme.md deleted file mode 100644 index 8562210..0000000 --- a/docs/readme.md +++ /dev/null @@ -1,32 +0,0 @@ -# adaptivetesting - -*adaptivetesting* is a Python package for computer-aided adaptive -testing that can be used to simulate and implement custom adaptive tests -in real-world testing scenarios. - -# Getting Started - ---- - -Required Python version: >= 3.11 (other versions may work, but they are not officially supported) - -```bash -pip install adaptivetesting -``` - -If you want to install the current development version, -you can do so by running the following command: - -```bash -pip install git+https://github.com/condecon/adaptivetesting -``` - -# Contents: - -* [data Module](adaptivetesting.data.md) -* [implementations Module](adaptivetesting.implementations.md) -* [math Module](adaptivetesting.math.md) -* [models Module](adaptivetesting.models.md) -* [simulation Module](adaptivetesting.simulation.md) -* [services Module](adaptivetesting.services.md) -* [tests Module](adaptivetesting.tests.md) diff --git a/docs/services.md b/docs/services.md deleted file mode 100644 index 082614a..0000000 --- a/docs/services.md +++ /dev/null @@ -1,42 +0,0 @@ -# services Module - -## IEstimator - -### *class* adaptivetesting.services.IEstimator(response_pattern: List[int] | Array, items: List[[TestItem](models.md#adaptivetesting.models.TestItem)], optimization_interval: Tuple[float, float] = (-10, 10)) - -Bases: `ABC` - -This is the interface required for every possible -estimator. -Any estimator inherits from this class and implements -the get_estimation method. - -Args: -: response_pattern (List[int]): list of responses (0: wrong, 1:right) -
- items (List[TestItem]): list of answered items - -#### *abstractmethod* get_estimation() → float - -Get the currently estimated ability. - -Returns: -: float: ability - -## ITestResults - -### *class* adaptivetesting.services.ITestResults(simulation_id: str, participant_id: int) - -Bases: `ABC` - -Interface for saving and reading test results. -This interface may mainly be used for saving simulation results. - -Args: -: simulation_id (str): The simulation ID. Name of the results file. -
- participant_id (int): The participant ID. - -#### *abstractmethod* load() → List[[TestResult](models.md#adaptivetesting.models.TestResult)] - -#### *abstractmethod* save(test_results: List[[TestResult](models.md#adaptivetesting.models.TestResult)]) → None diff --git a/docs/simulation.md b/docs/simulation.md deleted file mode 100644 index 6b6f4f5..0000000 --- a/docs/simulation.md +++ /dev/null @@ -1,53 +0,0 @@ -# simulation Module - -## ResultOutputFormat - -### *class* adaptivetesting.simulation.ResultOutputFormat(\*values) - -Bases: `Enum` - -Enum for selecting the output format for -the test results - -#### PICKLE *= 2* - -#### SQLITE *= 1* - -## StoppingCriterion - -### *class* adaptivetesting.simulation.StoppingCriterion(\*values) - -Bases: `Enum` - -Enum for selecting the stopping criterion -for the adaptive test - -#### LENGTH *= 2* - -#### SE *= 1* - -## Simulation - -### *class* adaptivetesting.simulation.Simulation(test: [AdaptiveTest](models.md#adaptivetesting.models.AdaptiveTest), test_result_output: [ResultOutputFormat](#adaptivetesting.simulation.ResultOutputFormat)) - -Bases: `object` - -This class can be used for simulating CAT. - -Args: -: test (AdaptiveTest): instance of an adaptive test implementation (see implementations module) -
- test_result_output (ResultOutputFormat): test results output format - -#### save_test_results() - -Saves the test results to the specified output format. - -#### simulate(criterion: [StoppingCriterion](#adaptivetesting.simulation.StoppingCriterion) = StoppingCriterion.SE, value: float = 0.4) - -Runs test until the stopping criterion is met. - -Args: -: criterion (StoppingCriterion): selected stopping criterion -
- value (float): either standard error value or test length value that has to be met by the test diff --git a/docs/source/_static/SPEC-0.svg b/docs/source/_static/SPEC-0.svg deleted file mode 100644 index d3e13e9..0000000 --- a/docs/source/_static/SPEC-0.svg +++ /dev/null @@ -1 +0,0 @@ -SPEC: 0SPEC0 \ No newline at end of file diff --git a/docs/source/_static/main.css b/docs/source/_static/main.css deleted file mode 100644 index 9298215..0000000 --- a/docs/source/_static/main.css +++ /dev/null @@ -1,24 +0,0 @@ -.logo{ - display: block; - margin: 0; - height: auto; - width: 100% !important; - border-radius: 0; - max-width: 100%; - background: transparent; -} - -.wy-side-nav-search { - display: block; - width: 300px; - padding: .809em; - margin-bottom: .809em; - z-index: 200; - background-color: white !important; - text-align: center; - color: #fcfcfc; -} - -.caption-text{ - color: white !important; -} \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100644 index d7dd04f..0000000 --- a/docs/source/index.rst +++ /dev/null @@ -1,37 +0,0 @@ -adaptivetesting -=========================================== - -*adaptivetesting* is a Python package for computer-aided adaptive -testing that can be used to simulate and implement custom adaptive tests -in real-world testing scenarios. - -Getting Started -================ -================ - -Required Python version: >= 3.11 (other versions may work, but they are not officially supported) - -.. code-block:: bash - - pip install adaptivetesting - - -If you want to install the current development version, -you can do so by running the following command: - -.. code-block:: bash - - pip install git+https://github.com/condecon/adaptivetesting - - -.. toctree:: - :maxdepth: 1 - :caption: Contents: - - data - implementations - math - models - simulation - services - tests diff --git a/docs/tests.md b/docs/tests.md deleted file mode 100644 index 8d3068d..0000000 --- a/docs/tests.md +++ /dev/null @@ -1,4 +0,0 @@ -# tests Module - -This module includes unit tests for the functionality of the package. -There is no explicit documentation available. diff --git a/examples/.gitignore b/examples/.gitignore deleted file mode 100644 index ff6bdd5..0000000 --- a/examples/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -item_pool.csv -data/ -*.pdf \ No newline at end of file diff --git a/examples/simulation.py b/examples/simulation.py deleted file mode 100644 index dcf5a6a..0000000 --- a/examples/simulation.py +++ /dev/null @@ -1,134 +0,0 @@ -# flake8: noqa -import pandas as pd -previc_item_pool = pd.read_csv("item_pool.csv") -previc_item_pool.head() - -from adaptivetesting.models import ItemPool -item_pool = ItemPool.load_from_list( - b=previc_item_pool["Difficulty"] -) - -from scipy.stats import norm -from numpy.random import seed -seed(1234) -theta_samples = norm.rvs(loc=0, scale=2, size=100) - - -from adaptivetesting.implementations import TestAssembler -from adaptivetesting.simulation import SimulationPool -from adaptivetesting.models import ResultOutputFormat, StoppingCriterion -from adaptivetesting.math.item_selection import maximum_information_criterion -from adaptivetesting.math.estimators import BayesModal, NormalPrior - -tests = [ - TestAssembler( - item_pool=item_pool, - simulation_id="example_bm", - participant_id=str(index), - ability_estimator=BayesModal, - estimator_args={ - "prior": NormalPrior(0,1), - "optimization_interval":(-10, 10) - }, - item_selector=maximum_information_criterion, - true_ability_level=theta, - simulation=True, - seed=index - ) - for index, theta in enumerate(theta_samples) -] - -sim_pool = SimulationPool( - adaptive_tests=tests, - test_result_output=ResultOutputFormat.CSV, - criterion=StoppingCriterion.SE, - value=0.4 -) -sim_pool.start() - -import os - -dfs = [] -for i in range(100): - filename = f"data/example_bm/{i}.csv" - if os.path.exists(filename): - try: - df = pd.read_csv(filename) - # Get the last row of every file - last_row = df.tail(1) - dfs.append(last_row) - # If there is an error, skip the file - except Exception: - pass -results_df = pd.concat(dfs, ignore_index=True) -mse = ((results_df["ability_estimation"] - results_df["true_ability_level"]) ** 2).mean() -print(f"MSE of ability estimates: {mse:.4f}") - - -import matplotlib.pyplot as plt - -fig, ax = plt.subplots() -ax.scatter(results_df["true_ability_level"], - results_df["ability_estimation"], - label="BM") -ax.plot(results_df["ability_estimation"], - results_df["ability_estimation"], - color="black") -ax.set_xlabel("True ability level") -ax.set_ylabel("Estimated ability level") -fig.savefig("sim_results_bm.pdf") - -# other example -from adaptivetesting.math.estimators import ExpectedAPosteriori, CustomPrior -from scipy.stats.distributions import t - -tests = [ - TestAssembler( - item_pool=item_pool, - simulation_id="example_eap", - participant_id=str(index), - ability_estimator=ExpectedAPosteriori, - estimator_args={ - "prior": CustomPrior(t, 3), - "optimization_interval":(-10, 10) - }, - item_selector=maximum_information_criterion, - true_ability_level=theta, - simulation=True, - seed=index - ) - for index, theta in enumerate(theta_samples) -] - -sim_pool = SimulationPool( - adaptive_tests=tests, - test_result_output=ResultOutputFormat.CSV, - criterion=StoppingCriterion.SE, - value=0.4 -) -sim_pool.start() - -dfs = [] -for i in range(100): - filename = f"data/example_eap/{i}.csv" - if os.path.exists(filename): - try: - df = pd.read_csv(filename) - # Get the last row of every file - last_row = df.tail(1) - dfs.append(last_row) - # If there is an error, skip the file - except Exception: - pass -results_df = pd.concat(dfs, ignore_index=True) -mse = ((results_df["ability_estimation"] - results_df["true_ability_level"]) ** 2).mean() -print(f"MSE of ability estimates: {mse:.4f}") - - -ax.scatter(results_df["true_ability_level"], - results_df["ability_estimation"], - label="EAP") -ax.set_xlabel("True ability level") -ax.set_ylabel("Estimated ability level") -ax.legend() -fig.savefig("sim_results_eap.pdf") diff --git a/examples/testing.py b/examples/testing.py deleted file mode 100644 index 0bca296..0000000 --- a/examples/testing.py +++ /dev/null @@ -1,108 +0,0 @@ -# flake8: noqa -# setup item pool -# the item pool is retrieved from the PREVIC -# https://github.com/manuelbohn/previc/tree/main/saves -import pandas as pd -previc_item_pool = pd.read_csv("item_pool.csv") -# add item column -previc_item_pool["id"] = list(range(1, 90)) -previc_item_pool.head() - -from adaptivetesting.models import ItemPool -item_pool = ItemPool.load_from_list( - b=previc_item_pool["Difficulty"], - ids=previc_item_pool["id"] -) - -# import psychopy -from psychopy import visual, event -from psychopy.hardware import keyboard -from adaptivetesting.implementations import TestAssembler -from adaptivetesting.models import AdaptiveTest, ItemPool, TestItem -from adaptivetesting.data import CSVContext -from adaptivetesting.math.estimators import ExpectedAPosteriori, CustomPrior -from adaptivetesting.math.item_selection import maximum_information_criterion -from scipy.stats import t -import pandas as pd - -# Create adaptive test -adaptive_test: AdaptiveTest = TestAssembler( - item_pool=item_pool, - simulation_id="example", - participant_id="dummy", - ability_estimator=ExpectedAPosteriori, - estimator_args={ - "prior": CustomPrior(t, 3), - "optimization_interval":(-10, 10) - }, - item_selector=maximum_information_criterion, - simulation=False, - debug=False -) - -# ==================== -# Setup PsychoPy -# ==================== - -# general setup -win = visual.Window([800, 600], - monitor="testMonitor", - units="deg", - fullscr=False) - -# init keyboard -keyboard.Keyboard() - - -# define function to get user input -def get_response(item: TestItem) -> int: - # select corresponding word from item pool data frame - stimuli: str = previc_item_pool[previc_item_pool["id"] == item.id]["word"].values[0] - - # create text box and display stimulus - text_box = visual.TextBox2(win=win, - text=stimuli, - alignment="center", - size=24) - # draw text - text_box.draw() - # update window - win.flip() - - # wait for pressed keys - while True: - keys = event.getKeys() - # if keys are not None - if keys: - # if the right arrow keys is pressed - # return 1 - if keys[0] == "right": - return 1 - # if the left arrow keys is pressed - # return 0 - if keys[0] == "left": - return 0 - - -# override adaptive test default function -adaptive_test.get_response = get_response - -# start adaptive test -while True: - adaptive_test.run_test_once() - - # check stopping criterion - if adaptive_test.standard_error <= 0.4: - break - - # end test if all items have been shown - if len(adaptive_test.item_pool.test_items) == 0: - break - -# save test results -data_context = CSVContext( - adaptive_test.simulation_id, - adaptive_test.participant_id -) - -data_context.save(adaptive_test.test_results) \ No newline at end of file diff --git a/images/default.svg b/images/default.svg deleted file mode 100644 index 844cbeb..0000000 --- a/images/default.svg +++ /dev/null @@ -1,208 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Item selection(Urry’s rule) - - - - - - - Presenting item to respondent - - - - - - - Ability estimation(MLE) - - - - - - - Checking stopping criterion - - - - - - - Initial ability level - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - End test - - - - - - - - - - - - - 0 - - - - - - true - - - - - - - - \ No newline at end of file diff --git a/images/semi-adaptive.svg b/images/semi-adaptive.svg deleted file mode 100644 index 96f20d1..0000000 --- a/images/semi-adaptive.svg +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Ability estimation (MLE) - - - - - - - Checking stopping criterion - - - - - - - Item selection(Urry’s rule) - - - - - - - Presenting item to respondent - - - - - - - Random item selection - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - End test - - - - - - - - - - - - - - - - - Presenting items to respondent - - - - - - - - - - - - Pretest - - - - - - Adaptive test - - - - - - - - - - - - - true - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/mypy.ini b/mypy.ini index f1a742f..061d4ff 100644 --- a/mypy.ini +++ b/mypy.ini @@ -5,4 +5,5 @@ files = adaptivetesting # Exclude the 'env' directory from type checking exclude = ^(setup\.py|env/.*) -check_untyped_defs = True \ No newline at end of file +check_untyped_defs = True +follow_untyped_imports = True \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index be210bc..2de1878 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name="adaptivetesting" -version="1.1.6" +version="1.2" description="adaptivetesting is a Python package that can be used to simulate and evaluate custom CAT scenarios as well as implement them in real-world testing scenarios from a single codebase" readme = "README.md" authors = [ @@ -8,26 +8,30 @@ authors = [ ] requires-python = ">=3.12" dependencies = [ - "numpy>=2.0.0", + "numpy>=2.1.0", "pandas>=2.3.0", - "scipy>=1.12.0", + "scipy>=1.15.0", "tqdm>=4.66.0", - "matplotlib>=3.9.0" + "matplotlib>=3.10.0", + "numdifftools>=0.9.42", ] -license-files=["LICENSE"] +license-files = ["LICENSE"] keywords=["statistics", "psychology", "item-response-theory", "computerized-adaptive-testing"] [build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" +requires = ["setuptools", "Cython"] +build-backend = "setuptools.build_meta" + [dependency-groups] dev = [ "adaptivetesting", + "cython>=3.1.4", "flake8>=7.2.0", "mypy>=1.15.0", - "pandas-stubs>=2.2.3.250308", - "scipy-stubs>=1.15.2.2", + "pandas-stubs>=2.3.0", + "scipy-stubs>=1.15.0", + "setuptools>=78.1.1", "snakeviz>=2.2.2", "types-tqdm>=4.67.0.20250516", ] @@ -38,14 +42,20 @@ docs = [ "sphinx-markdown-builder>=0.6.8", ] test = [ - "psychopy>=2025.1.1", + "psychopy", ] [tool.uv.sources] adaptivetesting = { workspace = true } +[tool.uv.workspace] +members = [ + ".", + ".", +] + [project.urls] Homepage = "https://github.com/condecon/adaptivetesting" -Documentation = "https://github.com/condecon/adaptivetesting/tree/main/docs" +Documentation = "https://github.com/condecon/adaptivetesting/wiki" Repository = "https://github.com/condecon/adaptivetesting.git" Issues = "https://github.com/condecon/adaptivetesting/issues" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 70e075f..0000000 Binary files a/requirements.txt and /dev/null differ diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..ba8b68f --- /dev/null +++ b/setup.py @@ -0,0 +1,21 @@ +from setuptools import setup, Extension, find_packages +from Cython.Build import cythonize +import glob +import os + +# Recursively find all .pyx files +pyx_files = glob.glob("adaptivetesting/**/*.pyx", recursive=True) +# Convert each file into an Extension +extensions = [ + Extension( + name=os.path.splitext(path.replace("/", ".").replace("\\", "."))[0], + sources=[path], + ) + for path in pyx_files +] + +setup( + name="adaptivetesting", + packages=find_packages(where="."), + ext_modules=cythonize(extensions, language_level="3"), +) diff --git a/test.ps1 b/test.ps1 new file mode 100644 index 0000000..b7523a3 --- /dev/null +++ b/test.ps1 @@ -0,0 +1,3 @@ +uv run mypy +uv run flake8 +uv run python -m unittest \ No newline at end of file diff --git a/uv.lock b/uv.lock index 6109162..a3ab08e 100644 --- a/uv.lock +++ b/uv.lock @@ -4,10 +4,16 @@ requires-python = ">=3.12" resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.14' and sys_platform == 'win32'", - "python_full_version < '3.14' and sys_platform == 'emscripten'", - "python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version >= '3.14' and sys_platform == 'darwin'", + "python_full_version >= '3.14' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'win32'", + "python_full_version < '3.13' and sys_platform == 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'emscripten'", + "python_full_version < '3.13' and sys_platform == 'emscripten'", + "python_full_version == '3.13.*' and sys_platform == 'darwin'", + "python_full_version < '3.13' and sys_platform == 'darwin'", + "python_full_version == '3.13.*' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version < '3.13' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] [[package]] @@ -24,10 +30,11 @@ wheels = [ [[package]] name = "adaptivetesting" -version = "1.1.6" +version = "1.2" source = { editable = "." } dependencies = [ { name = "matplotlib" }, + { name = "numdifftools" }, { name = "numpy" }, { name = "pandas" }, { name = "scipy" }, @@ -37,10 +44,12 @@ dependencies = [ [package.dev-dependencies] dev = [ { name = "adaptivetesting" }, + { name = "cython" }, { name = "flake8" }, { name = "mypy" }, { name = "pandas-stubs" }, { name = "scipy-stubs" }, + { name = "setuptools" }, { name = "snakeviz" }, { name = "types-tqdm" }, ] @@ -55,20 +64,23 @@ test = [ [package.metadata] requires-dist = [ - { name = "matplotlib", specifier = ">=3.9.0" }, - { name = "numpy", specifier = ">=2.0.0" }, + { name = "matplotlib", specifier = ">=3.10.0" }, + { name = "numdifftools", specifier = ">=0.9.42" }, + { name = "numpy", specifier = ">=2.1.0" }, { name = "pandas", specifier = ">=2.3.0" }, - { name = "scipy", specifier = ">=1.12.0" }, + { name = "scipy", specifier = ">=1.15.0" }, { name = "tqdm", specifier = ">=4.66.0" }, ] [package.metadata.requires-dev] dev = [ { name = "adaptivetesting", editable = "." }, + { name = "cython", specifier = ">=3.1.4" }, { name = "flake8", specifier = ">=7.2.0" }, { name = "mypy", specifier = ">=1.15.0" }, - { name = "pandas-stubs", specifier = ">=2.2.3.250308" }, - { name = "scipy-stubs", specifier = ">=1.15.2.2" }, + { name = "pandas-stubs", specifier = ">=2.3.0" }, + { name = "scipy-stubs", specifier = ">=1.15.0" }, + { name = "setuptools", specifier = ">=78.1.1" }, { name = "snakeviz", specifier = ">=2.2.2" }, { name = "types-tqdm", specifier = ">=4.67.0.20250516" }, ] @@ -77,7 +89,7 @@ docs = [ { name = "sphinx-book-theme", specifier = ">=1.1.3" }, { name = "sphinx-markdown-builder", specifier = ">=0.6.8" }, ] -test = [{ name = "psychopy", specifier = ">=2025.1.1" }] +test = [{ name = "psychopy" }] [[package]] name = "alabaster" @@ -88,6 +100,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929, upload-time = "2024-07-26T18:15:02.05Z" }, ] +[[package]] +name = "appdirs" +version = "1.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/d8/05696357e0311f5b5c316d7b95f46c669dd9c15aaeecbb48c7d0aeb88c40/appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", size = 13470, upload-time = "2020-05-11T07:59:51.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128", size = 9566, upload-time = "2020-05-11T07:59:49.499Z" }, +] + [[package]] name = "arabic-reshaper" version = "3.0.0" @@ -110,6 +131,62 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2b/03/13dde6512ad7b4557eb792fbcf0c653af6076b81e5941d36ec61f7ce6028/astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8", size = 12732, upload-time = "2019-12-22T18:12:11.297Z" }, ] +[[package]] +name = "audioop-lts" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/53/946db57842a50b2da2e0c1e34bd37f36f5aadba1a929a3971c5d7841dbca/audioop_lts-0.2.2.tar.gz", hash = "sha256:64d0c62d88e67b98a1a5e71987b7aa7b5bcffc7dcee65b635823dbdd0a8dbbd0", size = 30686, upload-time = "2025-08-05T16:43:17.409Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/d4/94d277ca941de5a507b07f0b592f199c22454eeaec8f008a286b3fbbacd6/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_universal2.whl", hash = "sha256:fd3d4602dc64914d462924a08c1a9816435a2155d74f325853c1f1ac3b2d9800", size = 46523, upload-time = "2025-08-05T16:42:20.836Z" }, + { url = "https://files.pythonhosted.org/packages/f8/5a/656d1c2da4b555920ce4177167bfeb8623d98765594af59702c8873f60ec/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_x86_64.whl", hash = "sha256:550c114a8df0aafe9a05442a1162dfc8fec37e9af1d625ae6060fed6e756f303", size = 27455, upload-time = "2025-08-05T16:42:22.283Z" }, + { url = "https://files.pythonhosted.org/packages/1b/83/ea581e364ce7b0d41456fb79d6ee0ad482beda61faf0cab20cbd4c63a541/audioop_lts-0.2.2-cp313-abi3-macosx_11_0_arm64.whl", hash = "sha256:9a13dc409f2564de15dd68be65b462ba0dde01b19663720c68c1140c782d1d75", size = 26997, upload-time = "2025-08-05T16:42:23.849Z" }, + { url = "https://files.pythonhosted.org/packages/b8/3b/e8964210b5e216e5041593b7d33e97ee65967f17c282e8510d19c666dab4/audioop_lts-0.2.2-cp313-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:51c916108c56aa6e426ce611946f901badac950ee2ddaf302b7ed35d9958970d", size = 85844, upload-time = "2025-08-05T16:42:25.208Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2e/0a1c52faf10d51def20531a59ce4c706cb7952323b11709e10de324d6493/audioop_lts-0.2.2-cp313-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47eba38322370347b1c47024defbd36374a211e8dd5b0dcbce7b34fdb6f8847b", size = 85056, upload-time = "2025-08-05T16:42:26.559Z" }, + { url = "https://files.pythonhosted.org/packages/75/e8/cd95eef479656cb75ab05dfece8c1f8c395d17a7c651d88f8e6e291a63ab/audioop_lts-0.2.2-cp313-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba7c3a7e5f23e215cb271516197030c32aef2e754252c4c70a50aaff7031a2c8", size = 93892, upload-time = "2025-08-05T16:42:27.902Z" }, + { url = "https://files.pythonhosted.org/packages/5c/1e/a0c42570b74f83efa5cca34905b3eef03f7ab09fe5637015df538a7f3345/audioop_lts-0.2.2-cp313-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:def246fe9e180626731b26e89816e79aae2276f825420a07b4a647abaa84becc", size = 96660, upload-time = "2025-08-05T16:42:28.9Z" }, + { url = "https://files.pythonhosted.org/packages/50/d5/8a0ae607ca07dbb34027bac8db805498ee7bfecc05fd2c148cc1ed7646e7/audioop_lts-0.2.2-cp313-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e160bf9df356d841bb6c180eeeea1834085464626dc1b68fa4e1d59070affdc3", size = 79143, upload-time = "2025-08-05T16:42:29.929Z" }, + { url = "https://files.pythonhosted.org/packages/12/17/0d28c46179e7910bfb0bb62760ccb33edb5de973052cb2230b662c14ca2e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4b4cd51a57b698b2d06cb9993b7ac8dfe89a3b2878e96bc7948e9f19ff51dba6", size = 84313, upload-time = "2025-08-05T16:42:30.949Z" }, + { url = "https://files.pythonhosted.org/packages/84/ba/bd5d3806641564f2024e97ca98ea8f8811d4e01d9b9f9831474bc9e14f9e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4a53aa7c16a60a6857e6b0b165261436396ef7293f8b5c9c828a3a203147ed4a", size = 93044, upload-time = "2025-08-05T16:42:31.959Z" }, + { url = "https://files.pythonhosted.org/packages/f9/5e/435ce8d5642f1f7679540d1e73c1c42d933331c0976eb397d1717d7f01a3/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:3fc38008969796f0f689f1453722a0f463da1b8a6fbee11987830bfbb664f623", size = 78766, upload-time = "2025-08-05T16:42:33.302Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3b/b909e76b606cbfd53875693ec8c156e93e15a1366a012f0b7e4fb52d3c34/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_s390x.whl", hash = "sha256:15ab25dd3e620790f40e9ead897f91e79c0d3ce65fe193c8ed6c26cffdd24be7", size = 87640, upload-time = "2025-08-05T16:42:34.854Z" }, + { url = "https://files.pythonhosted.org/packages/30/e7/8f1603b4572d79b775f2140d7952f200f5e6c62904585d08a01f0a70393a/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:03f061a1915538fd96272bac9551841859dbb2e3bf73ebe4a23ef043766f5449", size = 86052, upload-time = "2025-08-05T16:42:35.839Z" }, + { url = "https://files.pythonhosted.org/packages/b5/96/c37846df657ccdda62ba1ae2b6534fa90e2e1b1742ca8dcf8ebd38c53801/audioop_lts-0.2.2-cp313-abi3-win32.whl", hash = "sha256:3bcddaaf6cc5935a300a8387c99f7a7fbbe212a11568ec6cf6e4bc458c048636", size = 26185, upload-time = "2025-08-05T16:42:37.04Z" }, + { url = "https://files.pythonhosted.org/packages/34/a5/9d78fdb5b844a83da8a71226c7bdae7cc638861085fff7a1d707cb4823fa/audioop_lts-0.2.2-cp313-abi3-win_amd64.whl", hash = "sha256:a2c2a947fae7d1062ef08c4e369e0ba2086049a5e598fda41122535557012e9e", size = 30503, upload-time = "2025-08-05T16:42:38.427Z" }, + { url = "https://files.pythonhosted.org/packages/34/25/20d8fde083123e90c61b51afb547bb0ea7e77bab50d98c0ab243d02a0e43/audioop_lts-0.2.2-cp313-abi3-win_arm64.whl", hash = "sha256:5f93a5db13927a37d2d09637ccca4b2b6b48c19cd9eda7b17a2e9f77edee6a6f", size = 24173, upload-time = "2025-08-05T16:42:39.704Z" }, + { url = "https://files.pythonhosted.org/packages/58/a7/0a764f77b5c4ac58dc13c01a580f5d32ae8c74c92020b961556a43e26d02/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:73f80bf4cd5d2ca7814da30a120de1f9408ee0619cc75da87d0641273d202a09", size = 47096, upload-time = "2025-08-05T16:42:40.684Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ed/ebebedde1a18848b085ad0fa54b66ceb95f1f94a3fc04f1cd1b5ccb0ed42/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:106753a83a25ee4d6f473f2be6b0966fc1c9af7e0017192f5531a3e7463dce58", size = 27748, upload-time = "2025-08-05T16:42:41.992Z" }, + { url = "https://files.pythonhosted.org/packages/cb/6e/11ca8c21af79f15dbb1c7f8017952ee8c810c438ce4e2b25638dfef2b02c/audioop_lts-0.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fbdd522624141e40948ab3e8cdae6e04c748d78710e9f0f8d4dae2750831de19", size = 27329, upload-time = "2025-08-05T16:42:42.987Z" }, + { url = "https://files.pythonhosted.org/packages/84/52/0022f93d56d85eec5da6b9da6a958a1ef09e80c39f2cc0a590c6af81dcbb/audioop_lts-0.2.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:143fad0311e8209ece30a8dbddab3b65ab419cbe8c0dde6e8828da25999be911", size = 92407, upload-time = "2025-08-05T16:42:44.336Z" }, + { url = "https://files.pythonhosted.org/packages/87/1d/48a889855e67be8718adbc7a01f3c01d5743c325453a5e81cf3717664aad/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dfbbc74ec68a0fd08cfec1f4b5e8cca3d3cd7de5501b01c4b5d209995033cde9", size = 91811, upload-time = "2025-08-05T16:42:45.325Z" }, + { url = "https://files.pythonhosted.org/packages/98/a6/94b7213190e8077547ffae75e13ed05edc488653c85aa5c41472c297d295/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cfcac6aa6f42397471e4943e0feb2244549db5c5d01efcd02725b96af417f3fe", size = 100470, upload-time = "2025-08-05T16:42:46.468Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e9/78450d7cb921ede0cfc33426d3a8023a3bda755883c95c868ee36db8d48d/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:752d76472d9804ac60f0078c79cdae8b956f293177acd2316cd1e15149aee132", size = 103878, upload-time = "2025-08-05T16:42:47.576Z" }, + { url = "https://files.pythonhosted.org/packages/4f/e2/cd5439aad4f3e34ae1ee852025dc6aa8f67a82b97641e390bf7bd9891d3e/audioop_lts-0.2.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:83c381767e2cc10e93e40281a04852facc4cd9334550e0f392f72d1c0a9c5753", size = 84867, upload-time = "2025-08-05T16:42:49.003Z" }, + { url = "https://files.pythonhosted.org/packages/68/4b/9d853e9076c43ebba0d411e8d2aa19061083349ac695a7d082540bad64d0/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c0022283e9556e0f3643b7c3c03f05063ca72b3063291834cca43234f20c60bb", size = 90001, upload-time = "2025-08-05T16:42:50.038Z" }, + { url = "https://files.pythonhosted.org/packages/58/26/4bae7f9d2f116ed5593989d0e521d679b0d583973d203384679323d8fa85/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a2d4f1513d63c795e82948e1305f31a6d530626e5f9f2605408b300ae6095093", size = 99046, upload-time = "2025-08-05T16:42:51.111Z" }, + { url = "https://files.pythonhosted.org/packages/b2/67/a9f4fb3e250dda9e9046f8866e9fa7d52664f8985e445c6b4ad6dfb55641/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:c9c8e68d8b4a56fda8c025e538e639f8c5953f5073886b596c93ec9b620055e7", size = 84788, upload-time = "2025-08-05T16:42:52.198Z" }, + { url = "https://files.pythonhosted.org/packages/70/f7/3de86562db0121956148bcb0fe5b506615e3bcf6e63c4357a612b910765a/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:96f19de485a2925314f5020e85911fb447ff5fbef56e8c7c6927851b95533a1c", size = 94472, upload-time = "2025-08-05T16:42:53.59Z" }, + { url = "https://files.pythonhosted.org/packages/f1/32/fd772bf9078ae1001207d2df1eef3da05bea611a87dd0e8217989b2848fa/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e541c3ef484852ef36545f66209444c48b28661e864ccadb29daddb6a4b8e5f5", size = 92279, upload-time = "2025-08-05T16:42:54.632Z" }, + { url = "https://files.pythonhosted.org/packages/4f/41/affea7181592ab0ab560044632571a38edaf9130b84928177823fbf3176a/audioop_lts-0.2.2-cp313-cp313t-win32.whl", hash = "sha256:d5e73fa573e273e4f2e5ff96f9043858a5e9311e94ffefd88a3186a910c70917", size = 26568, upload-time = "2025-08-05T16:42:55.627Z" }, + { url = "https://files.pythonhosted.org/packages/28/2b/0372842877016641db8fc54d5c88596b542eec2f8f6c20a36fb6612bf9ee/audioop_lts-0.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9191d68659eda01e448188f60364c7763a7ca6653ed3f87ebb165822153a8547", size = 30942, upload-time = "2025-08-05T16:42:56.674Z" }, + { url = "https://files.pythonhosted.org/packages/ee/ca/baf2b9cc7e96c179bb4a54f30fcd83e6ecb340031bde68f486403f943768/audioop_lts-0.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c174e322bb5783c099aaf87faeb240c8d210686b04bd61dfd05a8e5a83d88969", size = 24603, upload-time = "2025-08-05T16:42:57.571Z" }, + { url = "https://files.pythonhosted.org/packages/5c/73/413b5a2804091e2c7d5def1d618e4837f1cb82464e230f827226278556b7/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:f9ee9b52f5f857fbaf9d605a360884f034c92c1c23021fb90b2e39b8e64bede6", size = 47104, upload-time = "2025-08-05T16:42:58.518Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8c/daa3308dc6593944410c2c68306a5e217f5c05b70a12e70228e7dd42dc5c/audioop_lts-0.2.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:49ee1a41738a23e98d98b937a0638357a2477bc99e61b0f768a8f654f45d9b7a", size = 27754, upload-time = "2025-08-05T16:43:00.132Z" }, + { url = "https://files.pythonhosted.org/packages/4e/86/c2e0f627168fcf61781a8f72cab06b228fe1da4b9fa4ab39cfb791b5836b/audioop_lts-0.2.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5b00be98ccd0fc123dcfad31d50030d25fcf31488cde9e61692029cd7394733b", size = 27332, upload-time = "2025-08-05T16:43:01.666Z" }, + { url = "https://files.pythonhosted.org/packages/c7/bd/35dce665255434f54e5307de39e31912a6f902d4572da7c37582809de14f/audioop_lts-0.2.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6d2e0f9f7a69403e388894d4ca5ada5c47230716a03f2847cfc7bd1ecb589d6", size = 92396, upload-time = "2025-08-05T16:43:02.991Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d2/deeb9f51def1437b3afa35aeb729d577c04bcd89394cb56f9239a9f50b6f/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9b0b8a03ef474f56d1a842af1a2e01398b8f7654009823c6d9e0ecff4d5cfbf", size = 91811, upload-time = "2025-08-05T16:43:04.096Z" }, + { url = "https://files.pythonhosted.org/packages/76/3b/09f8b35b227cee28cc8231e296a82759ed80c1a08e349811d69773c48426/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2b267b70747d82125f1a021506565bdc5609a2b24bcb4773c16d79d2bb260bbd", size = 100483, upload-time = "2025-08-05T16:43:05.085Z" }, + { url = "https://files.pythonhosted.org/packages/0b/15/05b48a935cf3b130c248bfdbdea71ce6437f5394ee8533e0edd7cfd93d5e/audioop_lts-0.2.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0337d658f9b81f4cd0fdb1f47635070cc084871a3d4646d9de74fdf4e7c3d24a", size = 103885, upload-time = "2025-08-05T16:43:06.197Z" }, + { url = "https://files.pythonhosted.org/packages/83/80/186b7fce6d35b68d3d739f228dc31d60b3412105854edb975aa155a58339/audioop_lts-0.2.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:167d3b62586faef8b6b2275c3218796b12621a60e43f7e9d5845d627b9c9b80e", size = 84899, upload-time = "2025-08-05T16:43:07.291Z" }, + { url = "https://files.pythonhosted.org/packages/49/89/c78cc5ac6cb5828f17514fb12966e299c850bc885e80f8ad94e38d450886/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0d9385e96f9f6da847f4d571ce3cb15b5091140edf3db97276872647ce37efd7", size = 89998, upload-time = "2025-08-05T16:43:08.335Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4b/6401888d0c010e586c2ca50fce4c903d70a6bb55928b16cfbdfd957a13da/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:48159d96962674eccdca9a3df280e864e8ac75e40a577cc97c5c42667ffabfc5", size = 99046, upload-time = "2025-08-05T16:43:09.367Z" }, + { url = "https://files.pythonhosted.org/packages/de/f8/c874ca9bb447dae0e2ef2e231f6c4c2b0c39e31ae684d2420b0f9e97ee68/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8fefe5868cd082db1186f2837d64cfbfa78b548ea0d0543e9b28935ccce81ce9", size = 84843, upload-time = "2025-08-05T16:43:10.749Z" }, + { url = "https://files.pythonhosted.org/packages/3e/c0/0323e66f3daebc13fd46b36b30c3be47e3fc4257eae44f1e77eb828c703f/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:58cf54380c3884fb49fdd37dfb7a772632b6701d28edd3e2904743c5e1773602", size = 94490, upload-time = "2025-08-05T16:43:12.131Z" }, + { url = "https://files.pythonhosted.org/packages/98/6b/acc7734ac02d95ab791c10c3f17ffa3584ccb9ac5c18fd771c638ed6d1f5/audioop_lts-0.2.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:088327f00488cdeed296edd9215ca159f3a5a5034741465789cad403fcf4bec0", size = 92297, upload-time = "2025-08-05T16:43:13.139Z" }, + { url = "https://files.pythonhosted.org/packages/13/c3/c3dc3f564ce6877ecd2a05f8d751b9b27a8c320c2533a98b0c86349778d0/audioop_lts-0.2.2-cp314-cp314t-win32.whl", hash = "sha256:068aa17a38b4e0e7de771c62c60bbca2455924b67a8814f3b0dee92b5820c0b3", size = 27331, upload-time = "2025-08-05T16:43:14.19Z" }, + { url = "https://files.pythonhosted.org/packages/72/bb/b4608537e9ffcb86449091939d52d24a055216a36a8bf66b936af8c3e7ac/audioop_lts-0.2.2-cp314-cp314t-win_amd64.whl", hash = "sha256:a5bf613e96f49712073de86f20dbdd4014ca18efd4d34ed18c75bd808337851b", size = 31697, upload-time = "2025-08-05T16:43:15.193Z" }, + { url = "https://files.pythonhosted.org/packages/f6/22/91616fe707a5c5510de2cac9b046a30defe7007ba8a0c04f9c08f27df312/audioop_lts-0.2.2-cp314-cp314t-win_arm64.whl", hash = "sha256:b492c3b040153e68b9fdaff5913305aaaba5bb433d8a7f73d5cf6a64ed3cc1dd", size = 25206, upload-time = "2025-08-05T16:43:16.444Z" }, +] + [[package]] name = "babel" version = "2.18.0" @@ -235,59 +312,75 @@ wheels = [ [[package]] name = "charset-normalizer" -version = "3.4.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/35/02daf95b9cd686320bb622eb148792655c9412dbb9b67abb5694e5910a24/charset_normalizer-3.4.5.tar.gz", hash = "sha256:95adae7b6c42a6c5b5b559b1a99149f090a57128155daeea91732c8d970d8644", size = 134804, upload-time = "2026-03-06T06:03:19.46Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/b6/9ee9c1a608916ca5feae81a344dffbaa53b26b90be58cc2159e3332d44ec/charset_normalizer-3.4.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed97c282ee4f994ef814042423a529df9497e3c666dca19be1d4cd1129dc7ade", size = 280976, upload-time = "2026-03-06T06:01:15.276Z" }, - { url = "https://files.pythonhosted.org/packages/f8/d8/a54f7c0b96f1df3563e9190f04daf981e365a9b397eedfdfb5dbef7e5c6c/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0294916d6ccf2d069727d65973c3a1ca477d68708db25fd758dd28b0827cff54", size = 189356, upload-time = "2026-03-06T06:01:16.511Z" }, - { url = "https://files.pythonhosted.org/packages/42/69/2bf7f76ce1446759a5787cb87d38f6a61eb47dbbdf035cfebf6347292a65/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dc57a0baa3eeedd99fafaef7511b5a6ef4581494e8168ee086031744e2679467", size = 206369, upload-time = "2026-03-06T06:01:17.853Z" }, - { url = "https://files.pythonhosted.org/packages/10/9c/949d1a46dab56b959d9a87272482195f1840b515a3380e39986989a893ae/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ed1a9a204f317ef879b32f9af507d47e49cd5e7f8e8d5d96358c98373314fc60", size = 203285, upload-time = "2026-03-06T06:01:19.473Z" }, - { url = "https://files.pythonhosted.org/packages/67/5c/ae30362a88b4da237d71ea214a8c7eb915db3eec941adda511729ac25fa2/charset_normalizer-3.4.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ad83b8f9379176c841f8865884f3514d905bcd2a9a3b210eaa446e7d2223e4d", size = 196274, upload-time = "2026-03-06T06:01:20.728Z" }, - { url = "https://files.pythonhosted.org/packages/b2/07/c9f2cb0e46cb6d64fdcc4f95953747b843bb2181bda678dc4e699b8f0f9a/charset_normalizer-3.4.5-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:a118e2e0b5ae6b0120d5efa5f866e58f2bb826067a646431da4d6a2bdae7950e", size = 184715, upload-time = "2026-03-06T06:01:22.194Z" }, - { url = "https://files.pythonhosted.org/packages/36/64/6b0ca95c44fddf692cd06d642b28f63009d0ce325fad6e9b2b4d0ef86a52/charset_normalizer-3.4.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:754f96058e61a5e22e91483f823e07df16416ce76afa4ebf306f8e1d1296d43f", size = 193426, upload-time = "2026-03-06T06:01:23.795Z" }, - { url = "https://files.pythonhosted.org/packages/50/bc/a730690d726403743795ca3f5bb2baf67838c5fea78236098f324b965e40/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0c300cefd9b0970381a46394902cd18eaf2aa00163f999590ace991989dcd0fc", size = 191780, upload-time = "2026-03-06T06:01:25.053Z" }, - { url = "https://files.pythonhosted.org/packages/97/4f/6c0bc9af68222b22951552d73df4532b5be6447cee32d58e7e8c74ecbb7b/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c108f8619e504140569ee7de3f97d234f0fbae338a7f9f360455071ef9855a95", size = 185805, upload-time = "2026-03-06T06:01:26.294Z" }, - { url = "https://files.pythonhosted.org/packages/dd/b9/a523fb9b0ee90814b503452b2600e4cbc118cd68714d57041564886e7325/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d1028de43596a315e2720a9849ee79007ab742c06ad8b45a50db8cdb7ed4a82a", size = 208342, upload-time = "2026-03-06T06:01:27.55Z" }, - { url = "https://files.pythonhosted.org/packages/4d/61/c59e761dee4464050713e50e27b58266cc8e209e518c0b378c1580c959ba/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:19092dde50335accf365cce21998a1c6dd8eafd42c7b226eb54b2747cdce2fac", size = 193661, upload-time = "2026-03-06T06:01:29.051Z" }, - { url = "https://files.pythonhosted.org/packages/1c/43/729fa30aad69783f755c5ad8649da17ee095311ca42024742701e202dc59/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4354e401eb6dab9aed3c7b4030514328a6c748d05e1c3e19175008ca7de84fb1", size = 204819, upload-time = "2026-03-06T06:01:30.298Z" }, - { url = "https://files.pythonhosted.org/packages/87/33/d9b442ce5a91b96fc0840455a9e49a611bbadae6122778d0a6a79683dd31/charset_normalizer-3.4.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a68766a3c58fde7f9aaa22b3786276f62ab2f594efb02d0a1421b6282e852e98", size = 198080, upload-time = "2026-03-06T06:01:31.478Z" }, - { url = "https://files.pythonhosted.org/packages/56/5a/b8b5a23134978ee9885cee2d6995f4c27cc41f9baded0a9685eabc5338f0/charset_normalizer-3.4.5-cp312-cp312-win32.whl", hash = "sha256:1827734a5b308b65ac54e86a618de66f935a4f63a8a462ff1e19a6788d6c2262", size = 132630, upload-time = "2026-03-06T06:01:33.056Z" }, - { url = "https://files.pythonhosted.org/packages/70/53/e44a4c07e8904500aec95865dc3f6464dc3586a039ef0df606eb3ac38e35/charset_normalizer-3.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:728c6a963dfab66ef865f49286e45239384249672cd598576765acc2a640a636", size = 142856, upload-time = "2026-03-06T06:01:34.489Z" }, - { url = "https://files.pythonhosted.org/packages/ea/aa/c5628f7cad591b1cf45790b7a61483c3e36cf41349c98af7813c483fd6e8/charset_normalizer-3.4.5-cp312-cp312-win_arm64.whl", hash = "sha256:75dfd1afe0b1647449e852f4fb428195a7ed0588947218f7ba929f6538487f02", size = 132982, upload-time = "2026-03-06T06:01:35.641Z" }, - { url = "https://files.pythonhosted.org/packages/f5/48/9f34ec4bb24aa3fdba1890c1bddb97c8a4be1bd84ef5c42ac2352563ad05/charset_normalizer-3.4.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ac59c15e3f1465f722607800c68713f9fbc2f672b9eb649fe831da4019ae9b23", size = 280788, upload-time = "2026-03-06T06:01:37.126Z" }, - { url = "https://files.pythonhosted.org/packages/0e/09/6003e7ffeb90cc0560da893e3208396a44c210c5ee42efff539639def59b/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:165c7b21d19365464e8f70e5ce5e12524c58b48c78c1f5a57524603c1ab003f8", size = 188890, upload-time = "2026-03-06T06:01:38.73Z" }, - { url = "https://files.pythonhosted.org/packages/42/1e/02706edf19e390680daa694d17e2b8eab4b5f7ac285e2a51168b4b22ee6b/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:28269983f25a4da0425743d0d257a2d6921ea7d9b83599d4039486ec5b9f911d", size = 206136, upload-time = "2026-03-06T06:01:40.016Z" }, - { url = "https://files.pythonhosted.org/packages/c7/87/942c3def1b37baf3cf786bad01249190f3ca3d5e63a84f831e704977de1f/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d27ce22ec453564770d29d03a9506d449efbb9fa13c00842262b2f6801c48cce", size = 202551, upload-time = "2026-03-06T06:01:41.522Z" }, - { url = "https://files.pythonhosted.org/packages/94/0a/af49691938dfe175d71b8a929bd7e4ace2809c0c5134e28bc535660d5262/charset_normalizer-3.4.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0625665e4ebdddb553ab185de5db7054393af8879fb0c87bd5690d14379d6819", size = 195572, upload-time = "2026-03-06T06:01:43.208Z" }, - { url = "https://files.pythonhosted.org/packages/20/ea/dfb1792a8050a8e694cfbde1570ff97ff74e48afd874152d38163d1df9ae/charset_normalizer-3.4.5-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:c23eb3263356d94858655b3e63f85ac5d50970c6e8febcdde7830209139cc37d", size = 184438, upload-time = "2026-03-06T06:01:44.755Z" }, - { url = "https://files.pythonhosted.org/packages/72/12/c281e2067466e3ddd0595bfaea58a6946765ace5c72dfa3edc2f5f118026/charset_normalizer-3.4.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e6302ca4ae283deb0af68d2fbf467474b8b6aedcd3dab4db187e07f94c109763", size = 193035, upload-time = "2026-03-06T06:01:46.051Z" }, - { url = "https://files.pythonhosted.org/packages/ba/4f/3792c056e7708e10464bad0438a44708886fb8f92e3c3d29ec5e2d964d42/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e51ae7d81c825761d941962450f50d041db028b7278e7b08930b4541b3e45cb9", size = 191340, upload-time = "2026-03-06T06:01:47.547Z" }, - { url = "https://files.pythonhosted.org/packages/e7/86/80ddba897127b5c7a9bccc481b0cd36c8fefa485d113262f0fe4332f0bf4/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:597d10dec876923e5c59e48dbd366e852eacb2b806029491d307daea6b917d7c", size = 185464, upload-time = "2026-03-06T06:01:48.764Z" }, - { url = "https://files.pythonhosted.org/packages/4d/00/b5eff85ba198faacab83e0e4b6f0648155f072278e3b392a82478f8b988b/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5cffde4032a197bd3b42fd0b9509ec60fb70918d6970e4cc773f20fc9180ca67", size = 208014, upload-time = "2026-03-06T06:01:50.371Z" }, - { url = "https://files.pythonhosted.org/packages/c8/11/d36f70be01597fd30850dde8a1269ebc8efadd23ba5785808454f2389bde/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2da4eedcb6338e2321e831a0165759c0c620e37f8cd044a263ff67493be8ffb3", size = 193297, upload-time = "2026-03-06T06:01:51.933Z" }, - { url = "https://files.pythonhosted.org/packages/1a/1d/259eb0a53d4910536c7c2abb9cb25f4153548efb42800c6a9456764649c0/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:65a126fb4b070d05340a84fc709dd9e7c75d9b063b610ece8a60197a291d0adf", size = 204321, upload-time = "2026-03-06T06:01:53.887Z" }, - { url = "https://files.pythonhosted.org/packages/84/31/faa6c5b9d3688715e1ed1bb9d124c384fe2fc1633a409e503ffe1c6398c1/charset_normalizer-3.4.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c7a80a9242963416bd81f99349d5f3fce1843c303bd404f204918b6d75a75fd6", size = 197509, upload-time = "2026-03-06T06:01:56.439Z" }, - { url = "https://files.pythonhosted.org/packages/fd/a5/c7d9dd1503ffc08950b3260f5d39ec2366dd08254f0900ecbcf3a6197c7c/charset_normalizer-3.4.5-cp313-cp313-win32.whl", hash = "sha256:f1d725b754e967e648046f00c4facc42d414840f5ccc670c5670f59f83693e4f", size = 132284, upload-time = "2026-03-06T06:01:57.812Z" }, - { url = "https://files.pythonhosted.org/packages/b9/0f/57072b253af40c8aa6636e6de7d75985624c1eb392815b2f934199340a89/charset_normalizer-3.4.5-cp313-cp313-win_amd64.whl", hash = "sha256:e37bd100d2c5d3ba35db9c7c5ba5a9228cbcffe5c4778dc824b164e5257813d7", size = 142630, upload-time = "2026-03-06T06:01:59.062Z" }, - { url = "https://files.pythonhosted.org/packages/31/41/1c4b7cc9f13bd9d369ce3bc993e13d374ce25fa38a2663644283ecf422c1/charset_normalizer-3.4.5-cp313-cp313-win_arm64.whl", hash = "sha256:93b3b2cc5cf1b8743660ce77a4f45f3f6d1172068207c1defc779a36eea6bb36", size = 133254, upload-time = "2026-03-06T06:02:00.281Z" }, - { url = "https://files.pythonhosted.org/packages/43/be/0f0fd9bb4a7fa4fb5067fb7d9ac693d4e928d306f80a0d02bde43a7c4aee/charset_normalizer-3.4.5-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8197abe5ca1ffb7d91e78360f915eef5addff270f8a71c1fc5be24a56f3e4873", size = 280232, upload-time = "2026-03-06T06:02:01.508Z" }, - { url = "https://files.pythonhosted.org/packages/28/02/983b5445e4bef49cd8c9da73a8e029f0825f39b74a06d201bfaa2e55142a/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2aecdb364b8a1802afdc7f9327d55dad5366bc97d8502d0f5854e50712dbc5f", size = 189688, upload-time = "2026-03-06T06:02:02.857Z" }, - { url = "https://files.pythonhosted.org/packages/d0/88/152745c5166437687028027dc080e2daed6fe11cfa95a22f4602591c42db/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a66aa5022bf81ab4b1bebfb009db4fd68e0c6d4307a1ce5ef6a26e5878dfc9e4", size = 206833, upload-time = "2026-03-06T06:02:05.127Z" }, - { url = "https://files.pythonhosted.org/packages/cb/0f/ebc15c8b02af2f19be9678d6eed115feeeccc45ce1f4b098d986c13e8769/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d77f97e515688bd615c1d1f795d540f32542d514242067adcb8ef532504cb9ee", size = 202879, upload-time = "2026-03-06T06:02:06.446Z" }, - { url = "https://files.pythonhosted.org/packages/38/9c/71336bff6934418dc8d1e8a1644176ac9088068bc571da612767619c97b3/charset_normalizer-3.4.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01a1ed54b953303ca7e310fafe0fe347aab348bd81834a0bcd602eb538f89d66", size = 195764, upload-time = "2026-03-06T06:02:08.763Z" }, - { url = "https://files.pythonhosted.org/packages/b7/95/ce92fde4f98615661871bc282a856cf9b8a15f686ba0af012984660d480b/charset_normalizer-3.4.5-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:b2d37d78297b39a9eb9eb92c0f6df98c706467282055419df141389b23f93362", size = 183728, upload-time = "2026-03-06T06:02:10.137Z" }, - { url = "https://files.pythonhosted.org/packages/1c/e7/f5b4588d94e747ce45ae680f0f242bc2d98dbd4eccfab73e6160b6893893/charset_normalizer-3.4.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e71bbb595973622b817c042bd943c3f3667e9c9983ce3d205f973f486fec98a7", size = 192937, upload-time = "2026-03-06T06:02:11.663Z" }, - { url = "https://files.pythonhosted.org/packages/f9/29/9d94ed6b929bf9f48bf6ede6e7474576499f07c4c5e878fb186083622716/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4cd966c2559f501c6fd69294d082c2934c8dd4719deb32c22961a5ac6db0df1d", size = 192040, upload-time = "2026-03-06T06:02:13.489Z" }, - { url = "https://files.pythonhosted.org/packages/15/d2/1a093a1cf827957f9445f2fe7298bcc16f8fc5e05c1ed2ad1af0b239035e/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:d5e52d127045d6ae01a1e821acfad2f3a1866c54d0e837828538fabe8d9d1bd6", size = 184107, upload-time = "2026-03-06T06:02:14.83Z" }, - { url = "https://files.pythonhosted.org/packages/0f/7d/82068ce16bd36135df7b97f6333c5d808b94e01d4599a682e2337ed5fd14/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:30a2b1a48478c3428d047ed9690d57c23038dac838a87ad624c85c0a78ebeb39", size = 208310, upload-time = "2026-03-06T06:02:16.165Z" }, - { url = "https://files.pythonhosted.org/packages/84/4e/4dfb52307bb6af4a5c9e73e482d171b81d36f522b21ccd28a49656baa680/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d8ed79b8f6372ca4254955005830fd61c1ccdd8c0fac6603e2c145c61dd95db6", size = 192918, upload-time = "2026-03-06T06:02:18.144Z" }, - { url = "https://files.pythonhosted.org/packages/08/a4/159ff7da662cf7201502ca89980b8f06acf3e887b278956646a8aeb178ab/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:c5af897b45fa606b12464ccbe0014bbf8c09191e0a66aab6aa9d5cf6e77e0c94", size = 204615, upload-time = "2026-03-06T06:02:19.821Z" }, - { url = "https://files.pythonhosted.org/packages/d6/62/0dd6172203cb6b429ffffc9935001fde42e5250d57f07b0c28c6046deb6b/charset_normalizer-3.4.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1088345bcc93c58d8d8f3d783eca4a6e7a7752bbff26c3eee7e73c597c191c2e", size = 197784, upload-time = "2026-03-06T06:02:21.86Z" }, - { url = "https://files.pythonhosted.org/packages/c7/5e/1aab5cb737039b9c59e63627dc8bbc0d02562a14f831cc450e5f91d84ce1/charset_normalizer-3.4.5-cp314-cp314-win32.whl", hash = "sha256:ee57b926940ba00bca7ba7041e665cc956e55ef482f851b9b65acb20d867e7a2", size = 133009, upload-time = "2026-03-06T06:02:23.289Z" }, - { url = "https://files.pythonhosted.org/packages/40/65/e7c6c77d7aaa4c0d7974f2e403e17f0ed2cb0fc135f77d686b916bf1eead/charset_normalizer-3.4.5-cp314-cp314-win_amd64.whl", hash = "sha256:4481e6da1830c8a1cc0b746b47f603b653dadb690bcd851d039ffaefe70533aa", size = 143511, upload-time = "2026-03-06T06:02:26.195Z" }, - { url = "https://files.pythonhosted.org/packages/ba/91/52b0841c71f152f563b8e072896c14e3d83b195c188b338d3cc2e582d1d4/charset_normalizer-3.4.5-cp314-cp314-win_arm64.whl", hash = "sha256:97ab7787092eb9b50fb47fa04f24c75b768a606af1bcba1957f07f128a7219e4", size = 133775, upload-time = "2026-03-06T06:02:27.473Z" }, - { url = "https://files.pythonhosted.org/packages/c5/60/3a621758945513adfd4db86827a5bafcc615f913dbd0b4c2ed64a65731be/charset_normalizer-3.4.5-py3-none-any.whl", hash = "sha256:9db5e3fcdcee89a78c04dffb3fe33c79f77bd741a624946db2591c81b2fc85b0", size = 55455, upload-time = "2026-03-06T06:03:17.827Z" }, +version = "3.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, + { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, + { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" }, + { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" }, + { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" }, + { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, + { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, + { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, + { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" }, + { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" }, + { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" }, + { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" }, + { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" }, + { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" }, + { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" }, + { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" }, + { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" }, + { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" }, + { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" }, + { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" }, + { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, + { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, + { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, + { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" }, + { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" }, + { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" }, + { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" }, + { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" }, + { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" }, + { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" }, + { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" }, + { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" }, + { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" }, + { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" }, + { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" }, + { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" }, + { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" }, + { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" }, + { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" }, + { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" }, + { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" }, + { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" }, + { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" }, + { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, ] [[package]] @@ -367,55 +460,55 @@ wheels = [ [[package]] name = "cryptography" -version = "46.0.5" +version = "46.0.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/60/04/ee2a9e8542e4fa2773b81771ff8349ff19cdd56b7258a0cc442639052edb/cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d", size = 750064, upload-time = "2026-02-10T19:18:38.255Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/81/b0bb27f2ba931a65409c6b8a8b358a7f03c0e46eceacddff55f7c84b1f3b/cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad", size = 7176289, upload-time = "2026-02-10T19:17:08.274Z" }, - { url = "https://files.pythonhosted.org/packages/ff/9e/6b4397a3e3d15123de3b1806ef342522393d50736c13b20ec4c9ea6693a6/cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b", size = 4275637, upload-time = "2026-02-10T19:17:10.53Z" }, - { url = "https://files.pythonhosted.org/packages/63/e7/471ab61099a3920b0c77852ea3f0ea611c9702f651600397ac567848b897/cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b", size = 4424742, upload-time = "2026-02-10T19:17:12.388Z" }, - { url = "https://files.pythonhosted.org/packages/37/53/a18500f270342d66bf7e4d9f091114e31e5ee9e7375a5aba2e85a91e0044/cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263", size = 4277528, upload-time = "2026-02-10T19:17:13.853Z" }, - { url = "https://files.pythonhosted.org/packages/22/29/c2e812ebc38c57b40e7c583895e73c8c5adb4d1e4a0cc4c5a4fdab2b1acc/cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d", size = 4947993, upload-time = "2026-02-10T19:17:15.618Z" }, - { url = "https://files.pythonhosted.org/packages/6b/e7/237155ae19a9023de7e30ec64e5d99a9431a567407ac21170a046d22a5a3/cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed", size = 4456855, upload-time = "2026-02-10T19:17:17.221Z" }, - { url = "https://files.pythonhosted.org/packages/2d/87/fc628a7ad85b81206738abbd213b07702bcbdada1dd43f72236ef3cffbb5/cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2", size = 3984635, upload-time = "2026-02-10T19:17:18.792Z" }, - { url = "https://files.pythonhosted.org/packages/84/29/65b55622bde135aedf4565dc509d99b560ee4095e56989e815f8fd2aa910/cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2", size = 4277038, upload-time = "2026-02-10T19:17:20.256Z" }, - { url = "https://files.pythonhosted.org/packages/bc/36/45e76c68d7311432741faf1fbf7fac8a196a0a735ca21f504c75d37e2558/cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0", size = 4912181, upload-time = "2026-02-10T19:17:21.825Z" }, - { url = "https://files.pythonhosted.org/packages/6d/1a/c1ba8fead184d6e3d5afcf03d569acac5ad063f3ac9fb7258af158f7e378/cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731", size = 4456482, upload-time = "2026-02-10T19:17:25.133Z" }, - { url = "https://files.pythonhosted.org/packages/f9/e5/3fb22e37f66827ced3b902cf895e6a6bc1d095b5b26be26bd13c441fdf19/cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82", size = 4405497, upload-time = "2026-02-10T19:17:26.66Z" }, - { url = "https://files.pythonhosted.org/packages/1a/df/9d58bb32b1121a8a2f27383fabae4d63080c7ca60b9b5c88be742be04ee7/cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1", size = 4667819, upload-time = "2026-02-10T19:17:28.569Z" }, - { url = "https://files.pythonhosted.org/packages/ea/ed/325d2a490c5e94038cdb0117da9397ece1f11201f425c4e9c57fe5b9f08b/cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48", size = 3028230, upload-time = "2026-02-10T19:17:30.518Z" }, - { url = "https://files.pythonhosted.org/packages/e9/5a/ac0f49e48063ab4255d9e3b79f5def51697fce1a95ea1370f03dc9db76f6/cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4", size = 3480909, upload-time = "2026-02-10T19:17:32.083Z" }, - { url = "https://files.pythonhosted.org/packages/00/13/3d278bfa7a15a96b9dc22db5a12ad1e48a9eb3d40e1827ef66a5df75d0d0/cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2", size = 7119287, upload-time = "2026-02-10T19:17:33.801Z" }, - { url = "https://files.pythonhosted.org/packages/67/c8/581a6702e14f0898a0848105cbefd20c058099e2c2d22ef4e476dfec75d7/cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678", size = 4265728, upload-time = "2026-02-10T19:17:35.569Z" }, - { url = "https://files.pythonhosted.org/packages/dd/4a/ba1a65ce8fc65435e5a849558379896c957870dd64fecea97b1ad5f46a37/cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87", size = 4408287, upload-time = "2026-02-10T19:17:36.938Z" }, - { url = "https://files.pythonhosted.org/packages/f8/67/8ffdbf7b65ed1ac224d1c2df3943553766914a8ca718747ee3871da6107e/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee", size = 4270291, upload-time = "2026-02-10T19:17:38.748Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e5/f52377ee93bc2f2bba55a41a886fd208c15276ffbd2569f2ddc89d50e2c5/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981", size = 4927539, upload-time = "2026-02-10T19:17:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/3b/02/cfe39181b02419bbbbcf3abdd16c1c5c8541f03ca8bda240debc467d5a12/cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9", size = 4442199, upload-time = "2026-02-10T19:17:41.789Z" }, - { url = "https://files.pythonhosted.org/packages/c0/96/2fcaeb4873e536cf71421a388a6c11b5bc846e986b2b069c79363dc1648e/cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648", size = 3960131, upload-time = "2026-02-10T19:17:43.379Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d2/b27631f401ddd644e94c5cf33c9a4069f72011821cf3dc7309546b0642a0/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4", size = 4270072, upload-time = "2026-02-10T19:17:45.481Z" }, - { url = "https://files.pythonhosted.org/packages/f4/a7/60d32b0370dae0b4ebe55ffa10e8599a2a59935b5ece1b9f06edb73abdeb/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0", size = 4892170, upload-time = "2026-02-10T19:17:46.997Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b9/cf73ddf8ef1164330eb0b199a589103c363afa0cf794218c24d524a58eab/cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663", size = 4441741, upload-time = "2026-02-10T19:17:48.661Z" }, - { url = "https://files.pythonhosted.org/packages/5f/eb/eee00b28c84c726fe8fa0158c65afe312d9c3b78d9d01daf700f1f6e37ff/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826", size = 4396728, upload-time = "2026-02-10T19:17:50.058Z" }, - { url = "https://files.pythonhosted.org/packages/65/f4/6bc1a9ed5aef7145045114b75b77c2a8261b4d38717bd8dea111a63c3442/cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d", size = 4652001, upload-time = "2026-02-10T19:17:51.54Z" }, - { url = "https://files.pythonhosted.org/packages/86/ef/5d00ef966ddd71ac2e6951d278884a84a40ffbd88948ef0e294b214ae9e4/cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a", size = 3003637, upload-time = "2026-02-10T19:17:52.997Z" }, - { url = "https://files.pythonhosted.org/packages/b7/57/f3f4160123da6d098db78350fdfd9705057aad21de7388eacb2401dceab9/cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4", size = 3469487, upload-time = "2026-02-10T19:17:54.549Z" }, - { url = "https://files.pythonhosted.org/packages/e2/fa/a66aa722105ad6a458bebd64086ca2b72cdd361fed31763d20390f6f1389/cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31", size = 7170514, upload-time = "2026-02-10T19:17:56.267Z" }, - { url = "https://files.pythonhosted.org/packages/0f/04/c85bdeab78c8bc77b701bf0d9bdcf514c044e18a46dcff330df5448631b0/cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18", size = 4275349, upload-time = "2026-02-10T19:17:58.419Z" }, - { url = "https://files.pythonhosted.org/packages/5c/32/9b87132a2f91ee7f5223b091dc963055503e9b442c98fc0b8a5ca765fab0/cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235", size = 4420667, upload-time = "2026-02-10T19:18:00.619Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a6/a7cb7010bec4b7c5692ca6f024150371b295ee1c108bdc1c400e4c44562b/cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a", size = 4276980, upload-time = "2026-02-10T19:18:02.379Z" }, - { url = "https://files.pythonhosted.org/packages/8e/7c/c4f45e0eeff9b91e3f12dbd0e165fcf2a38847288fcfd889deea99fb7b6d/cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76", size = 4939143, upload-time = "2026-02-10T19:18:03.964Z" }, - { url = "https://files.pythonhosted.org/packages/37/19/e1b8f964a834eddb44fa1b9a9976f4e414cbb7aa62809b6760c8803d22d1/cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614", size = 4453674, upload-time = "2026-02-10T19:18:05.588Z" }, - { url = "https://files.pythonhosted.org/packages/db/ed/db15d3956f65264ca204625597c410d420e26530c4e2943e05a0d2f24d51/cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229", size = 3978801, upload-time = "2026-02-10T19:18:07.167Z" }, - { url = "https://files.pythonhosted.org/packages/41/e2/df40a31d82df0a70a0daf69791f91dbb70e47644c58581d654879b382d11/cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1", size = 4276755, upload-time = "2026-02-10T19:18:09.813Z" }, - { url = "https://files.pythonhosted.org/packages/33/45/726809d1176959f4a896b86907b98ff4391a8aa29c0aaaf9450a8a10630e/cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d", size = 4901539, upload-time = "2026-02-10T19:18:11.263Z" }, - { url = "https://files.pythonhosted.org/packages/99/0f/a3076874e9c88ecb2ecc31382f6e7c21b428ede6f55aafa1aa272613e3cd/cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c", size = 4452794, upload-time = "2026-02-10T19:18:12.914Z" }, - { url = "https://files.pythonhosted.org/packages/02/ef/ffeb542d3683d24194a38f66ca17c0a4b8bf10631feef44a7ef64e631b1a/cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4", size = 4404160, upload-time = "2026-02-10T19:18:14.375Z" }, - { url = "https://files.pythonhosted.org/packages/96/93/682d2b43c1d5f1406ed048f377c0fc9fc8f7b0447a478d5c65ab3d3a66eb/cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9", size = 4667123, upload-time = "2026-02-10T19:18:15.886Z" }, - { url = "https://files.pythonhosted.org/packages/45/2d/9c5f2926cb5300a8eefc3f4f0b3f3df39db7f7ce40c8365444c49363cbda/cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72", size = 3010220, upload-time = "2026-02-10T19:18:17.361Z" }, - { url = "https://files.pythonhosted.org/packages/48/ef/0c2f4a8e31018a986949d34a01115dd057bf536905dca38897bacd21fac3/cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595", size = 3467050, upload-time = "2026-02-10T19:18:18.899Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz", hash = "sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", size = 750652, upload-time = "2026-04-08T01:57:54.692Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", size = 7179869, upload-time = "2026-04-08T01:56:17.157Z" }, + { url = "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", size = 4275492, upload-time = "2026-04-08T01:56:19.36Z" }, + { url = "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", size = 4426670, upload-time = "2026-04-08T01:56:21.415Z" }, + { url = "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", size = 4280275, upload-time = "2026-04-08T01:56:23.539Z" }, + { url = "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", size = 4928402, upload-time = "2026-04-08T01:56:25.624Z" }, + { url = "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", size = 4459985, upload-time = "2026-04-08T01:56:27.309Z" }, + { url = "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de", size = 3990652, upload-time = "2026-04-08T01:56:29.095Z" }, + { url = "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", size = 4279805, upload-time = "2026-04-08T01:56:30.928Z" }, + { url = "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", size = 4892883, upload-time = "2026-04-08T01:56:32.614Z" }, + { url = "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", size = 4459756, upload-time = "2026-04-08T01:56:34.306Z" }, + { url = "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", size = 4410244, upload-time = "2026-04-08T01:56:35.977Z" }, + { url = "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", size = 4674868, upload-time = "2026-04-08T01:56:38.034Z" }, + { url = "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl", hash = "sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", size = 3026504, upload-time = "2026-04-08T01:56:39.666Z" }, + { url = "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl", hash = "sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", size = 3488363, upload-time = "2026-04-08T01:56:41.893Z" }, + { url = "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:d151173275e1728cf7839aaa80c34fe550c04ddb27b34f48c232193df8db5842", size = 7119671, upload-time = "2026-04-08T01:56:44Z" }, + { url = "https://files.pythonhosted.org/packages/74/66/e3ce040721b0b5599e175ba91ab08884c75928fbeb74597dd10ef13505d2/cryptography-46.0.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:db0f493b9181c7820c8134437eb8b0b4792085d37dbb24da050476ccb664e59c", size = 4268551, upload-time = "2026-04-08T01:56:46.071Z" }, + { url = "https://files.pythonhosted.org/packages/03/11/5e395f961d6868269835dee1bafec6a1ac176505a167f68b7d8818431068/cryptography-46.0.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ebd6daf519b9f189f85c479427bbd6e9c9037862cf8fe89ee35503bd209ed902", size = 4408887, upload-time = "2026-04-08T01:56:47.718Z" }, + { url = "https://files.pythonhosted.org/packages/40/53/8ed1cf4c3b9c8e611e7122fb56f1c32d09e1fff0f1d77e78d9ff7c82653e/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:b7b412817be92117ec5ed95f880defe9cf18a832e8cafacf0a22337dc1981b4d", size = 4271354, upload-time = "2026-04-08T01:56:49.312Z" }, + { url = "https://files.pythonhosted.org/packages/50/46/cf71e26025c2e767c5609162c866a78e8a2915bbcfa408b7ca495c6140c4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:fbfd0e5f273877695cb93baf14b185f4878128b250cc9f8e617ea0c025dfb022", size = 4905845, upload-time = "2026-04-08T01:56:50.916Z" }, + { url = "https://files.pythonhosted.org/packages/c0/ea/01276740375bac6249d0a971ebdf6b4dc9ead0ee0a34ef3b5a88c1a9b0d4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ffca7aa1d00cf7d6469b988c581598f2259e46215e0140af408966a24cf086ce", size = 4444641, upload-time = "2026-04-08T01:56:52.882Z" }, + { url = "https://files.pythonhosted.org/packages/3d/4c/7d258f169ae71230f25d9f3d06caabcff8c3baf0978e2b7d65e0acac3827/cryptography-46.0.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:60627cf07e0d9274338521205899337c5d18249db56865f943cbe753aa96f40f", size = 3967749, upload-time = "2026-04-08T01:56:54.597Z" }, + { url = "https://files.pythonhosted.org/packages/b5/2a/2ea0767cad19e71b3530e4cad9605d0b5e338b6a1e72c37c9c1ceb86c333/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:80406c3065e2c55d7f49a9550fe0c49b3f12e5bfff5dedb727e319e1afb9bf99", size = 4270942, upload-time = "2026-04-08T01:56:56.416Z" }, + { url = "https://files.pythonhosted.org/packages/41/3d/fe14df95a83319af25717677e956567a105bb6ab25641acaa093db79975d/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:c5b1ccd1239f48b7151a65bc6dd54bcfcc15e028c8ac126d3fada09db0e07ef1", size = 4871079, upload-time = "2026-04-08T01:56:58.31Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/4a479e0f36f8f378d397f4eab4c850b4ffb79a2f0d58704b8fa0703ddc11/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:d5f7520159cd9c2154eb61eb67548ca05c5774d39e9c2c4339fd793fe7d097b2", size = 4443999, upload-time = "2026-04-08T01:57:00.508Z" }, + { url = "https://files.pythonhosted.org/packages/28/17/b59a741645822ec6d04732b43c5d35e4ef58be7bfa84a81e5ae6f05a1d33/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fcd8eac50d9138c1d7fc53a653ba60a2bee81a505f9f8850b6b2888555a45d0e", size = 4399191, upload-time = "2026-04-08T01:57:02.654Z" }, + { url = "https://files.pythonhosted.org/packages/59/6a/bb2e166d6d0e0955f1e9ff70f10ec4b2824c9cfcdb4da772c7dd69cc7d80/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:65814c60f8cc400c63131584e3e1fad01235edba2614b61fbfbfa954082db0ee", size = 4655782, upload-time = "2026-04-08T01:57:04.592Z" }, + { url = "https://files.pythonhosted.org/packages/95/b6/3da51d48415bcb63b00dc17c2eff3a651b7c4fed484308d0f19b30e8cb2c/cryptography-46.0.7-cp314-cp314t-win32.whl", hash = "sha256:fdd1736fed309b4300346f88f74cd120c27c56852c3838cab416e7a166f67298", size = 3002227, upload-time = "2026-04-08T01:57:06.91Z" }, + { url = "https://files.pythonhosted.org/packages/32/a8/9f0e4ed57ec9cebe506e58db11ae472972ecb0c659e4d52bbaee80ca340a/cryptography-46.0.7-cp314-cp314t-win_amd64.whl", hash = "sha256:e06acf3c99be55aa3b516397fe42f5855597f430add9c17fa46bf2e0fb34c9bb", size = 3475332, upload-time = "2026-04-08T01:57:08.807Z" }, + { url = "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", size = 7165618, upload-time = "2026-04-08T01:57:10.645Z" }, + { url = "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", size = 4270628, upload-time = "2026-04-08T01:57:12.885Z" }, + { url = "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", size = 4415405, upload-time = "2026-04-08T01:57:14.923Z" }, + { url = "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", size = 4272715, upload-time = "2026-04-08T01:57:16.638Z" }, + { url = "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", size = 4918400, upload-time = "2026-04-08T01:57:19.021Z" }, + { url = "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", size = 4450634, upload-time = "2026-04-08T01:57:21.185Z" }, + { url = "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", size = 3985233, upload-time = "2026-04-08T01:57:22.862Z" }, + { url = "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", size = 4271955, upload-time = "2026-04-08T01:57:24.814Z" }, + { url = "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", size = 4879888, upload-time = "2026-04-08T01:57:26.88Z" }, + { url = "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", size = 4449961, upload-time = "2026-04-08T01:57:29.068Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", size = 4401696, upload-time = "2026-04-08T01:57:31.029Z" }, + { url = "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", size = 4664256, upload-time = "2026-04-08T01:57:33.144Z" }, + { url = "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl", hash = "sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", size = 3013001, upload-time = "2026-04-08T01:57:34.933Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl", hash = "sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", size = 3472985, upload-time = "2026-04-08T01:57:36.714Z" }, ] [[package]] @@ -427,13 +520,43 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, ] +[[package]] +name = "cython" +version = "3.2.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/91/85/7574c9cd44b69a27210444b6650f6477f56c75fee1b70d7672d3e4166167/cython-3.2.4.tar.gz", hash = "sha256:84226ecd313b233da27dc2eb3601b4f222b8209c3a7216d8733b031da1dc64e6", size = 3280291, upload-time = "2026-01-04T14:14:14.473Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/4d/1eb0c7c196a136b1926f4d7f0492a96c6fabd604d77e6cd43b56a3a16d83/cython-3.2.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:64d7f71be3dd6d6d4a4c575bb3a4674ea06d1e1e5e4cd1b9882a2bc40ed3c4c9", size = 2970064, upload-time = "2026-01-04T14:15:08.567Z" }, + { url = "https://files.pythonhosted.org/packages/03/1c/46e34b08bea19a1cdd1e938a4c123e6299241074642db9d81983cef95e9f/cython-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:869487ea41d004f8b92171f42271fbfadb1ec03bede3158705d16cd570d6b891", size = 3226757, upload-time = "2026-01-04T14:15:10.812Z" }, + { url = "https://files.pythonhosted.org/packages/12/33/3298a44d201c45bcf0d769659725ae70e9c6c42adf8032f6d89c8241098d/cython-3.2.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:55b6c44cd30821f0b25220ceba6fe636ede48981d2a41b9bbfe3c7902ce44ea7", size = 3388969, upload-time = "2026-01-04T14:15:12.45Z" }, + { url = "https://files.pythonhosted.org/packages/bb/f3/4275cd3ea0a4cf4606f9b92e7f8766478192010b95a7f516d1b7cf22cb10/cython-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:767b143704bdd08a563153448955935844e53b852e54afdc552b43902ed1e235", size = 2756457, upload-time = "2026-01-04T14:15:14.67Z" }, + { url = "https://files.pythonhosted.org/packages/18/b5/1cfca43b7d20a0fdb1eac67313d6bb6b18d18897f82dd0f17436bdd2ba7f/cython-3.2.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:28e8075087a59756f2d059273184b8b639fe0f16cf17470bd91c39921bc154e0", size = 2960506, upload-time = "2026-01-04T14:15:16.733Z" }, + { url = "https://files.pythonhosted.org/packages/71/bb/8f28c39c342621047fea349a82fac712a5e2b37546d2f737bbde48d5143d/cython-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03893c88299a2c868bb741ba6513357acd104e7c42265809fd58dce1456a36fc", size = 3213148, upload-time = "2026-01-04T14:15:18.804Z" }, + { url = "https://files.pythonhosted.org/packages/7a/d2/16fa02f129ed2b627e88d9d9ebd5ade3eeb66392ae5ba85b259d2d52b047/cython-3.2.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f81eda419b5ada7b197bbc3c5f4494090e3884521ffd75a3876c93fbf66c9ca8", size = 3375764, upload-time = "2026-01-04T14:15:20.817Z" }, + { url = "https://files.pythonhosted.org/packages/91/3f/deb8f023a5c10c0649eb81332a58c180fad27c7533bb4aae138b5bc34d92/cython-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:83266c356c13c68ffe658b4905279c993d8a5337bb0160fa90c8a3e297ea9a2e", size = 2754238, upload-time = "2026-01-04T14:15:23.001Z" }, + { url = "https://files.pythonhosted.org/packages/ee/d7/3bda3efce0c5c6ce79cc21285dbe6f60369c20364e112f5a506ee8a1b067/cython-3.2.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d4b4fd5332ab093131fa6172e8362f16adef3eac3179fd24bbdc392531cb82fa", size = 2971496, upload-time = "2026-01-04T14:15:25.038Z" }, + { url = "https://files.pythonhosted.org/packages/89/ed/1021ffc80b9c4720b7ba869aea8422c82c84245ef117ebe47a556bdc00c3/cython-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e3b5ac54e95f034bc7fb07313996d27cbf71abc17b229b186c1540942d2dc28e", size = 3256146, upload-time = "2026-01-04T14:15:26.741Z" }, + { url = "https://files.pythonhosted.org/packages/0c/51/ca221ec7e94b3c5dc4138dcdcbd41178df1729c1e88c5dfb25f9d30ba3da/cython-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90f43be4eaa6afd58ce20d970bb1657a3627c44e1760630b82aa256ba74b4acb", size = 3383458, upload-time = "2026-01-04T14:15:28.425Z" }, + { url = "https://files.pythonhosted.org/packages/79/2e/1388fc0243240cd54994bb74f26aaaf3b2e22f89d3a2cf8da06d75d46ca2/cython-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:983f9d2bb8a896e16fa68f2b37866ded35fa980195eefe62f764ddc5f9f5ef8e", size = 2791241, upload-time = "2026-01-04T14:15:30.448Z" }, + { url = "https://files.pythonhosted.org/packages/0a/8b/fd393f0923c82be4ec0db712fffb2ff0a7a131707b842c99bf24b549274d/cython-3.2.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:36bf3f5eb56d5281aafabecbaa6ed288bc11db87547bba4e1e52943ae6961ccf", size = 2875622, upload-time = "2026-01-04T14:15:39.749Z" }, + { url = "https://files.pythonhosted.org/packages/73/48/48530d9b9d64ec11dbe0dd3178a5fe1e0b27977c1054ecffb82be81e9b6a/cython-3.2.4-cp39-abi3-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6d5267f22b6451eb1e2e1b88f6f78a2c9c8733a6ddefd4520d3968d26b824581", size = 3210669, upload-time = "2026-01-04T14:15:41.911Z" }, + { url = "https://files.pythonhosted.org/packages/5e/91/4865fbfef1f6bb4f21d79c46104a53d1a3fa4348286237e15eafb26e0828/cython-3.2.4-cp39-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3b6e58f73a69230218d5381817850ce6d0da5bb7e87eb7d528c7027cbba40b06", size = 2856835, upload-time = "2026-01-04T14:15:43.815Z" }, + { url = "https://files.pythonhosted.org/packages/fa/39/60317957dbef179572398253f29d28f75f94ab82d6d39ea3237fb6c89268/cython-3.2.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e71efb20048358a6b8ec604a0532961c50c067b5e63e345e2e359fff72feaee8", size = 2994408, upload-time = "2026-01-04T14:15:45.422Z" }, + { url = "https://files.pythonhosted.org/packages/8d/30/7c24d9292650db4abebce98abc9b49c820d40fa7c87921c0a84c32f4efe7/cython-3.2.4-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:28b1e363b024c4b8dcf52ff68125e635cb9cb4b0ba997d628f25e32543a71103", size = 2891478, upload-time = "2026-01-04T14:15:47.394Z" }, + { url = "https://files.pythonhosted.org/packages/86/70/03dc3c962cde9da37a93cca8360e576f904d5f9beecfc9d70b1f820d2e5f/cython-3.2.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:31a90b4a2c47bb6d56baeb926948348ec968e932c1ae2c53239164e3e8880ccf", size = 3225663, upload-time = "2026-01-04T14:15:49.446Z" }, + { url = "https://files.pythonhosted.org/packages/b1/97/10b50c38313c37b1300325e2e53f48ea9a2c078a85c0c9572057135e31d5/cython-3.2.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e65e4773021f8dc8532010b4fbebe782c77f9a0817e93886e518c93bd6a44e9d", size = 3115628, upload-time = "2026-01-04T14:15:51.323Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b1/d6a353c9b147848122a0db370863601fdf56de2d983b5c4a6a11e6ee3cd7/cython-3.2.4-cp39-abi3-win32.whl", hash = "sha256:2b1f12c0e4798293d2754e73cd6f35fa5bbdf072bdc14bc6fc442c059ef2d290", size = 2437463, upload-time = "2026-01-04T14:15:53.787Z" }, + { url = "https://files.pythonhosted.org/packages/2d/d8/319a1263b9c33b71343adfd407e5daffd453daef47ebc7b642820a8b68ed/cython-3.2.4-cp39-abi3-win_arm64.whl", hash = "sha256:3b8e62049afef9da931d55de82d8f46c9a147313b69d5ff6af6e9121d545ce7a", size = 2442754, upload-time = "2026-01-04T14:15:55.382Z" }, + { url = "https://files.pythonhosted.org/packages/ff/fa/d3c15189f7c52aaefbaea76fb012119b04b9013f4bf446cb4eb4c26c4e6b/cython-3.2.4-py3-none-any.whl", hash = "sha256:732fc93bc33ae4b14f6afaca663b916c2fdd5dcbfad7114e17fb2434eeaea45c", size = 1257078, upload-time = "2026-01-04T14:14:12.373Z" }, +] + [[package]] name = "decorator" -version = "4.4.2" +version = "5.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/93/84fa12f2dc341f8cf5f022ee09e109961055749df2d0c75c5f98746cfe6c/decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7", size = 33629, upload-time = "2020-02-29T05:24:43.312Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/1b/72a1821152d07cf1d8b6fce298aeb06a7eb90f4d6d41acec9861e7cc6df0/decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760", size = 9239, upload-time = "2020-02-29T05:24:45.993Z" }, + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, ] [[package]] @@ -461,12 +584,15 @@ source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/17/0e/e9c0c4d86142c529a62996d290e2f7d15cc4f214acf5386adc102191af94/dukpy-0.2.3.tar.gz", hash = "sha256:cc8dd158326f95231d320da80be6e6a1d72bbaad9de2569eaffb6af736f45e6b", size = 1867359, upload-time = "2020-06-09T22:14:14.949Z" } [[package]] -name = "elementpath" -version = "5.1.1" +name = "egi-pynetstation" +version = "1.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/95/eeb61a2a917bf506d1402748e71c62399d8dcdd8cdccd64c81962832c260/elementpath-5.1.1.tar.gz", hash = "sha256:c4d1bd6aed987258354d0ea004d965eb0a6818213326bd4fd9bde5dacdb20277", size = 375378, upload-time = "2026-01-20T21:42:27.175Z" } +dependencies = [ + { name = "ntplib" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/44/e2e185795cffb40ef4a37ac6c31ae007ce3eae2b196b70568e72e9ae37e5/egi_pynetstation-1.0.1.tar.gz", hash = "sha256:f2b5c41ffad40e8c0320e4d43e5cbc2f184f1aa933680b57e1d1bc976942f2af", size = 24382, upload-time = "2023-11-01T23:23:42.358Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/5a/4ddfd9aeecdc75a78b5d85d882abc2b822115caae2c00a4d0eb23cc101fc/elementpath-5.1.1-py3-none-any.whl", hash = "sha256:57637359065e60654422d8474c1749b09bb21348012b7197f868027e3c09c9b9", size = 259962, upload-time = "2026-01-20T21:42:24.127Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5d/d7d4ba8a0c2e8d22cb2db7a9df0041d64e0fa11fcd05fe168d4ee9d13007/egi_pynetstation-1.0.1-py3-none-any.whl", hash = "sha256:46f7d73d4fff19f0cef16a1119267f3a30a0c3437d74e0f146fa63e0c9aaf53b", size = 29163, upload-time = "2023-11-01T23:23:40.894Z" }, ] [[package]] @@ -520,43 +646,43 @@ wheels = [ [[package]] name = "fonttools" -version = "4.62.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/96/686339e0fda8142b7ebed39af53f4a5694602a729662f42a6209e3be91d0/fonttools-4.62.0.tar.gz", hash = "sha256:0dc477c12b8076b4eb9af2e440421b0433ffa9e1dcb39e0640a6c94665ed1098", size = 3579521, upload-time = "2026-03-09T16:50:06.217Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/9d/7ad1ffc080619f67d0b1e0fa6a0578f0be077404f13fd8e448d1616a94a3/fonttools-4.62.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:22bde4dc12a9e09b5ced77f3b5053d96cf10c4976c6ac0dee293418ef289d221", size = 2870004, upload-time = "2026-03-09T16:48:50.837Z" }, - { url = "https://files.pythonhosted.org/packages/4d/8b/ba59069a490f61b737e064c3129453dbd28ee38e81d56af0d04d7e6b4de4/fonttools-4.62.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7199c73b326bad892f1cb53ffdd002128bfd58a89b8f662204fbf1daf8d62e85", size = 2414662, upload-time = "2026-03-09T16:48:53.295Z" }, - { url = "https://files.pythonhosted.org/packages/8c/8c/c52a4310de58deeac7e9ea800892aec09b00bb3eb0c53265b31ec02be115/fonttools-4.62.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d732938633681d6e2324e601b79e93f7f72395ec8681f9cdae5a8c08bc167e72", size = 5032975, upload-time = "2026-03-09T16:48:55.718Z" }, - { url = "https://files.pythonhosted.org/packages/0b/a1/d16318232964d786907b9b3613b8409f74cf0be2da400854509d3a864e43/fonttools-4.62.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:31a804c16d76038cc4e3826e07678efb0a02dc4f15396ea8e07088adbfb2578e", size = 4988544, upload-time = "2026-03-09T16:48:57.715Z" }, - { url = "https://files.pythonhosted.org/packages/b2/8d/7e745ca3e65852adc5e52a83dc213fe1b07d61cb5b394970fcd4b1199d1e/fonttools-4.62.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:090e74ac86e68c20150e665ef8e7e0c20cb9f8b395302c9419fa2e4d332c3b51", size = 4971296, upload-time = "2026-03-09T16:48:59.678Z" }, - { url = "https://files.pythonhosted.org/packages/e6/d4/b717a4874175146029ca1517e85474b1af80c9d9a306fc3161e71485eea5/fonttools-4.62.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8f086120e8be9e99ca1288aa5ce519833f93fe0ec6ebad2380c1dee18781f0b5", size = 5122503, upload-time = "2026-03-09T16:49:02.464Z" }, - { url = "https://files.pythonhosted.org/packages/cb/4b/92cfcba4bf8373f51c49c5ae4b512ead6fbda7d61a0e8c35a369d0db40a0/fonttools-4.62.0-cp312-cp312-win32.whl", hash = "sha256:37a73e5e38fd05c637daede6ffed5f3496096be7df6e4a3198d32af038f87527", size = 2281060, upload-time = "2026-03-09T16:49:04.385Z" }, - { url = "https://files.pythonhosted.org/packages/cd/06/cc96468781a4dc8ae2f14f16f32b32f69bde18cb9384aad27ccc7adf76f7/fonttools-4.62.0-cp312-cp312-win_amd64.whl", hash = "sha256:658ab837c878c4d2a652fcbb319547ea41693890e6434cf619e66f79387af3b8", size = 2331193, upload-time = "2026-03-09T16:49:06.598Z" }, - { url = "https://files.pythonhosted.org/packages/82/c7/985c1670aa6d82ef270f04cde11394c168f2002700353bd2bde405e59b8f/fonttools-4.62.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:274c8b8a87e439faf565d3bcd3f9f9e31bca7740755776a4a90a4bfeaa722efa", size = 2864929, upload-time = "2026-03-09T16:49:09.331Z" }, - { url = "https://files.pythonhosted.org/packages/c1/dc/c409c8ceec0d3119e9ab0b7b1a2e3c76d1f4d66e4a9db5c59e6b7652e7df/fonttools-4.62.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93e27131a5a0ae82aaadcffe309b1bae195f6711689722af026862bede05c07c", size = 2412586, upload-time = "2026-03-09T16:49:11.378Z" }, - { url = "https://files.pythonhosted.org/packages/5f/ac/8e300dbf7b4d135287c261ffd92ede02d9f48f0d2db14665fbc8b059588a/fonttools-4.62.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83c6524c5b93bad9c2939d88e619fedc62e913c19e673f25d5ab74e7a5d074e5", size = 5013708, upload-time = "2026-03-09T16:49:14.063Z" }, - { url = "https://files.pythonhosted.org/packages/fb/bc/60d93477b653eeb1ddf5f9ec34be689b79234d82dbdded269ac0252715b8/fonttools-4.62.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:106aec9226f9498fc5345125ff7200842c01eda273ae038f5049b0916907acee", size = 4964355, upload-time = "2026-03-09T16:49:16.515Z" }, - { url = "https://files.pythonhosted.org/packages/cb/eb/6dc62bcc3c3598c28a3ecb77e69018869c3e109bd83031d4973c059d318b/fonttools-4.62.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:15d86b96c79013320f13bc1b15f94789edb376c0a2d22fb6088f33637e8dfcbc", size = 4953472, upload-time = "2026-03-09T16:49:18.494Z" }, - { url = "https://files.pythonhosted.org/packages/82/b3/3af7592d9b254b7b7fec018135f8776bfa0d1ad335476c2791b1334dc5e4/fonttools-4.62.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f16c07e5250d5d71d0f990a59460bc5620c3cc456121f2cfb5b60475699905f", size = 5094701, upload-time = "2026-03-09T16:49:21.67Z" }, - { url = "https://files.pythonhosted.org/packages/31/3d/976645583ab567d3ee75ff87b33aa1330fa2baeeeae5fc46210b4274dd45/fonttools-4.62.0-cp313-cp313-win32.whl", hash = "sha256:d31558890f3fa00d4f937d12708f90c7c142c803c23eaeb395a71f987a77ebe3", size = 2279710, upload-time = "2026-03-09T16:49:23.812Z" }, - { url = "https://files.pythonhosted.org/packages/f5/7a/e25245a30457595740041dba9d0ea8ec1b2517f2f1a6a741f15eba1a4edc/fonttools-4.62.0-cp313-cp313-win_amd64.whl", hash = "sha256:6826a5aa53fb6def8a66bf423939745f415546c4e92478a7c531b8b6282b6c3b", size = 2330291, upload-time = "2026-03-09T16:49:26.237Z" }, - { url = "https://files.pythonhosted.org/packages/1a/64/61f69298aa6e7c363dcf00dd6371a654676900abe27d1effd1a74b43e5d0/fonttools-4.62.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:4fa5a9c716e2f75ef34b5a5c2ca0ee4848d795daa7e6792bf30fd4abf8993449", size = 2864222, upload-time = "2026-03-09T16:49:28.285Z" }, - { url = "https://files.pythonhosted.org/packages/c6/57/6b08756fe4455336b1fe160ab3c11fccc90768ccb6ee03fb0b45851aace4/fonttools-4.62.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:625f5cbeb0b8f4e42343eaeb4bc2786718ddd84760a2f5e55fdd3db049047c00", size = 2410674, upload-time = "2026-03-09T16:49:30.504Z" }, - { url = "https://files.pythonhosted.org/packages/6f/86/db65b63bb1b824b63e602e9be21b18741ddc99bcf5a7850f9181159ae107/fonttools-4.62.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6247e58b96b982709cd569a91a2ba935d406dccf17b6aa615afaed37ac3856aa", size = 4999387, upload-time = "2026-03-09T16:49:32.593Z" }, - { url = "https://files.pythonhosted.org/packages/86/c8/c6669e42d2f4efd60d38a3252cebbb28851f968890efb2b9b15f9d1092b0/fonttools-4.62.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:840632ea9c1eab7b7f01c369e408c0721c287dfd7500ab937398430689852fd1", size = 4912506, upload-time = "2026-03-09T16:49:34.927Z" }, - { url = "https://files.pythonhosted.org/packages/2e/49/0ae552aa098edd0ec548413fbf818f52ceb70535016215094a5ce9bf8f70/fonttools-4.62.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:28a9ea2a7467a816d1bec22658b0cce4443ac60abac3e293bdee78beb74588f3", size = 4951202, upload-time = "2026-03-09T16:49:37.1Z" }, - { url = "https://files.pythonhosted.org/packages/71/65/ae38fc8a4cea6f162d74cf11f58e9aeef1baa7d0e3d1376dabd336c129e5/fonttools-4.62.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5ae611294f768d413949fd12693a8cba0e6332fbc1e07aba60121be35eac68d0", size = 5060758, upload-time = "2026-03-09T16:49:39.464Z" }, - { url = "https://files.pythonhosted.org/packages/db/3d/bb797496f35c60544cd5af71ffa5aad62df14ef7286908d204cb5c5096fe/fonttools-4.62.0-cp314-cp314-win32.whl", hash = "sha256:273acb61f316d07570a80ed5ff0a14a23700eedbec0ad968b949abaa4d3f6bb5", size = 2283496, upload-time = "2026-03-09T16:49:42.448Z" }, - { url = "https://files.pythonhosted.org/packages/2e/9f/91081ffe5881253177c175749cce5841f5ec6e931f5d52f4a817207b7429/fonttools-4.62.0-cp314-cp314-win_amd64.whl", hash = "sha256:a5f974006d14f735c6c878fc4b117ad031dc93638ddcc450ca69f8fd64d5e104", size = 2335426, upload-time = "2026-03-09T16:49:44.228Z" }, - { url = "https://files.pythonhosted.org/packages/f8/65/f47f9b3db1ec156a1f222f1089ba076b2cc9ee1d024a8b0a60c54258517e/fonttools-4.62.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0361a7d41d86937f1f752717c19f719d0fde064d3011038f9f19bdf5fc2f5c95", size = 2947079, upload-time = "2026-03-09T16:49:46.471Z" }, - { url = "https://files.pythonhosted.org/packages/52/73/bc62e5058a0c22cf02b1e0169ef0c3ca6c3247216d719f95bead3c05a991/fonttools-4.62.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4108c12773b3c97aa592311557c405d5b4fc03db2b969ed928fcf68e7b3c887", size = 2448802, upload-time = "2026-03-09T16:49:48.328Z" }, - { url = "https://files.pythonhosted.org/packages/2b/df/bfaa0e845884935355670e6e68f137185ab87295f8bc838db575e4a66064/fonttools-4.62.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b448075f32708e8fb377fe7687f769a5f51a027172c591ba9a58693631b077a8", size = 5137378, upload-time = "2026-03-09T16:49:50.223Z" }, - { url = "https://files.pythonhosted.org/packages/32/32/04f616979a18b48b52e634988b93d847b6346260faf85ecccaf7e2e9057f/fonttools-4.62.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5f1fa8cc9f1a56a3e33ee6b954d6d9235e6b9d11eb7a6c9dfe2c2f829dc24db", size = 4920714, upload-time = "2026-03-09T16:49:53.172Z" }, - { url = "https://files.pythonhosted.org/packages/3b/2e/274e16689c1dfee5c68302cd7c444213cfddd23cf4620374419625037ec6/fonttools-4.62.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f8c8ea812f82db1e884b9cdb663080453e28f0f9a1f5027a5adb59c4cc8d38d1", size = 5016012, upload-time = "2026-03-09T16:49:55.762Z" }, - { url = "https://files.pythonhosted.org/packages/7f/0c/b08117270626e7117ac2f89d732fdd4386ec37d2ab3a944462d29e6f89a1/fonttools-4.62.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:03c6068adfdc67c565d217e92386b1cdd951abd4240d65180cec62fa74ba31b2", size = 5042766, upload-time = "2026-03-09T16:49:57.726Z" }, - { url = "https://files.pythonhosted.org/packages/11/83/a48b73e54efa272ee65315a6331b30a9b3a98733310bc11402606809c50e/fonttools-4.62.0-cp314-cp314t-win32.whl", hash = "sha256:d28d5baacb0017d384df14722a63abe6e0230d8ce642b1615a27d78ffe3bc983", size = 2347785, upload-time = "2026-03-09T16:49:59.698Z" }, - { url = "https://files.pythonhosted.org/packages/f8/27/c67eab6dc3525bdc39586511b1b3d7161e972dacc0f17476dbaf932e708b/fonttools-4.62.0-cp314-cp314t-win_amd64.whl", hash = "sha256:3f9e20c4618f1e04190c802acae6dc337cb6db9fa61e492fd97cd5c5a9ff6d07", size = 2413914, upload-time = "2026-03-09T16:50:02.251Z" }, - { url = "https://files.pythonhosted.org/packages/9c/57/c2487c281dde03abb2dec244fd67059b8d118bd30a653cbf69e94084cb23/fonttools-4.62.0-py3-none-any.whl", hash = "sha256:75064f19a10c50c74b336aa5ebe7b1f89fd0fb5255807bfd4b0c6317098f4af3", size = 1152427, upload-time = "2026-03-09T16:50:04.074Z" }, +version = "4.62.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/08/7012b00a9a5874311b639c3920270c36ee0c445b69d9989a85e5c92ebcb0/fonttools-4.62.1.tar.gz", hash = "sha256:e54c75fd6041f1122476776880f7c3c3295ffa31962dc6ebe2543c00dca58b5d", size = 3580737, upload-time = "2026-03-13T13:54:25.52Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/d4/dbacced3953544b9a93088cc10ef2b596d348c983d5c67a404fa41ec51ba/fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:90365821debbd7db678809c7491ca4acd1e0779b9624cdc6ddaf1f31992bf974", size = 2870219, upload-time = "2026-03-13T13:52:53.664Z" }, + { url = "https://files.pythonhosted.org/packages/66/9e/a769c8e99b81e5a87ab7e5e7236684de4e96246aae17274e5347d11ebd78/fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12859ff0b47dd20f110804c3e0d0970f7b832f561630cd879969011541a464a9", size = 2414891, upload-time = "2026-03-13T13:52:56.493Z" }, + { url = "https://files.pythonhosted.org/packages/69/64/f19a9e3911968c37e1e620e14dfc5778299e1474f72f4e57c5ec771d9489/fonttools-4.62.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c125ffa00c3d9003cdaaf7f2c79e6e535628093e14b5de1dccb08859b680936", size = 5033197, upload-time = "2026-03-13T13:52:59.179Z" }, + { url = "https://files.pythonhosted.org/packages/9b/8a/99c8b3c3888c5c474c08dbfd7c8899786de9604b727fcefb055b42c84bba/fonttools-4.62.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:149f7d84afca659d1a97e39a4778794a2f83bf344c5ee5134e09995086cc2392", size = 4988768, upload-time = "2026-03-13T13:53:02.761Z" }, + { url = "https://files.pythonhosted.org/packages/d1/c6/0f904540d3e6ab463c1243a0d803504826a11604c72dd58c2949796a1762/fonttools-4.62.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0aa72c43a601cfa9273bb1ae0518f1acadc01ee181a6fc60cd758d7fdadffc04", size = 4971512, upload-time = "2026-03-13T13:53:05.678Z" }, + { url = "https://files.pythonhosted.org/packages/29/0b/5cbef6588dc9bd6b5c9ad6a4d5a8ca384d0cea089da31711bbeb4f9654a6/fonttools-4.62.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:19177c8d96c7c36359266e571c5173bcee9157b59cfc8cb0153c5673dc5a3a7d", size = 5122723, upload-time = "2026-03-13T13:53:08.662Z" }, + { url = "https://files.pythonhosted.org/packages/4a/47/b3a5342d381595ef439adec67848bed561ab7fdb1019fa522e82101b7d9c/fonttools-4.62.1-cp312-cp312-win32.whl", hash = "sha256:a24decd24d60744ee8b4679d38e88b8303d86772053afc29b19d23bb8207803c", size = 2281278, upload-time = "2026-03-13T13:53:10.998Z" }, + { url = "https://files.pythonhosted.org/packages/28/b1/0c2ab56a16f409c6c8a68816e6af707827ad5d629634691ff60a52879792/fonttools-4.62.1-cp312-cp312-win_amd64.whl", hash = "sha256:9e7863e10b3de72376280b515d35b14f5eeed639d1aa7824f4cf06779ec65e42", size = 2331414, upload-time = "2026-03-13T13:53:13.992Z" }, + { url = "https://files.pythonhosted.org/packages/3b/56/6f389de21c49555553d6a5aeed5ac9767631497ac836c4f076273d15bd72/fonttools-4.62.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c22b1014017111c401469e3acc5433e6acf6ebcc6aa9efb538a533c800971c79", size = 2865155, upload-time = "2026-03-13T13:53:16.132Z" }, + { url = "https://files.pythonhosted.org/packages/03/c5/0e3966edd5ec668d41dfe418787726752bc07e2f5fd8c8f208615e61fa89/fonttools-4.62.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68959f5fc58ed4599b44aad161c2837477d7f35f5f79402d97439974faebfebe", size = 2412802, upload-time = "2026-03-13T13:53:18.878Z" }, + { url = "https://files.pythonhosted.org/packages/52/94/e6ac4b44026de7786fe46e3bfa0c87e51d5d70a841054065d49cd62bb909/fonttools-4.62.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef46db46c9447103b8f3ff91e8ba009d5fe181b1920a83757a5762551e32bb68", size = 5013926, upload-time = "2026-03-13T13:53:21.379Z" }, + { url = "https://files.pythonhosted.org/packages/e2/98/8b1e801939839d405f1f122e7d175cebe9aeb4e114f95bfc45e3152af9a7/fonttools-4.62.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6706d1cb1d5e6251a97ad3c1b9347505c5615c112e66047abbef0f8545fa30d1", size = 4964575, upload-time = "2026-03-13T13:53:23.857Z" }, + { url = "https://files.pythonhosted.org/packages/46/76/7d051671e938b1881670528fec69cc4044315edd71a229c7fd712eaa5119/fonttools-4.62.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2e7abd2b1e11736f58c1de27819e1955a53267c21732e78243fa2fa2e5c1e069", size = 4953693, upload-time = "2026-03-13T13:53:26.569Z" }, + { url = "https://files.pythonhosted.org/packages/1f/ae/b41f8628ec0be3c1b934fc12b84f4576a5c646119db4d3bdd76a217c90b5/fonttools-4.62.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:403d28ce06ebfc547fbcb0cb8b7f7cc2f7a2d3e1a67ba9a34b14632df9e080f9", size = 5094920, upload-time = "2026-03-13T13:53:29.329Z" }, + { url = "https://files.pythonhosted.org/packages/f2/f6/53a1e9469331a23dcc400970a27a4caa3d9f6edbf5baab0260285238b884/fonttools-4.62.1-cp313-cp313-win32.whl", hash = "sha256:93c316e0f5301b2adbe6a5f658634307c096fd5aae60a5b3412e4f3e1728ab24", size = 2279928, upload-time = "2026-03-13T13:53:32.352Z" }, + { url = "https://files.pythonhosted.org/packages/38/60/35186529de1db3c01f5ad625bde07c1f576305eab6d86bbda4c58445f721/fonttools-4.62.1-cp313-cp313-win_amd64.whl", hash = "sha256:7aa21ff53e28a9c2157acbc44e5b401149d3c9178107130e82d74ceb500e5056", size = 2330514, upload-time = "2026-03-13T13:53:34.991Z" }, + { url = "https://files.pythonhosted.org/packages/36/f0/2888cdac391807d68d90dcb16ef858ddc1b5309bfc6966195a459dd326e2/fonttools-4.62.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fa1d16210b6b10a826d71bed68dd9ec24a9e218d5a5e2797f37c573e7ec215ca", size = 2864442, upload-time = "2026-03-13T13:53:37.509Z" }, + { url = "https://files.pythonhosted.org/packages/4b/b2/e521803081f8dc35990816b82da6360fa668a21b44da4b53fc9e77efcd62/fonttools-4.62.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:aa69d10ed420d8121118e628ad47d86e4caa79ba37f968597b958f6cceab7eca", size = 2410901, upload-time = "2026-03-13T13:53:40.55Z" }, + { url = "https://files.pythonhosted.org/packages/00/a4/8c3511ff06e53110039358dbbdc1a65d72157a054638387aa2ada300a8b8/fonttools-4.62.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd13b7999d59c5eb1c2b442eb2d0c427cb517a0b7a1f5798fc5c9e003f5ff782", size = 4999608, upload-time = "2026-03-13T13:53:42.798Z" }, + { url = "https://files.pythonhosted.org/packages/28/63/cd0c3b26afe60995a5295f37c246a93d454023726c3261cfbb3559969bb9/fonttools-4.62.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8d337fdd49a79b0d51c4da87bc38169d21c3abbf0c1aa9367eff5c6656fb6dae", size = 4912726, upload-time = "2026-03-13T13:53:45.405Z" }, + { url = "https://files.pythonhosted.org/packages/70/b9/ac677cb07c24c685cf34f64e140617d58789d67a3dd524164b63648c6114/fonttools-4.62.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d241cdc4a67b5431c6d7f115fdf63335222414995e3a1df1a41e1182acd4bcc7", size = 4951422, upload-time = "2026-03-13T13:53:48.326Z" }, + { url = "https://files.pythonhosted.org/packages/e6/10/11c08419a14b85b7ca9a9faca321accccc8842dd9e0b1c8a72908de05945/fonttools-4.62.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c05557a78f8fa514da0f869556eeda40887a8abc77c76ee3f74cf241778afd5a", size = 5060979, upload-time = "2026-03-13T13:53:51.366Z" }, + { url = "https://files.pythonhosted.org/packages/4e/3c/12eea4a4cf054e7ab058ed5ceada43b46809fce2bf319017c4d63ae55bb4/fonttools-4.62.1-cp314-cp314-win32.whl", hash = "sha256:49a445d2f544ce4a69338694cad575ba97b9a75fff02720da0882d1a73f12800", size = 2283733, upload-time = "2026-03-13T13:53:53.606Z" }, + { url = "https://files.pythonhosted.org/packages/6b/67/74b070029043186b5dd13462c958cb7c7f811be0d2e634309d9a1ffb1505/fonttools-4.62.1-cp314-cp314-win_amd64.whl", hash = "sha256:1eecc128c86c552fb963fe846ca4e011b1be053728f798185a1687502f6d398e", size = 2335663, upload-time = "2026-03-13T13:53:56.23Z" }, + { url = "https://files.pythonhosted.org/packages/42/c5/4d2ed3ca6e33617fc5624467da353337f06e7f637707478903c785bd8e20/fonttools-4.62.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:1596aeaddf7f78e21e68293c011316a25267b3effdaccaf4d59bc9159d681b82", size = 2947288, upload-time = "2026-03-13T13:53:59.397Z" }, + { url = "https://files.pythonhosted.org/packages/1f/e9/7ab11ddfda48ed0f89b13380e5595ba572619c27077be0b2c447a63ff351/fonttools-4.62.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:8f8fca95d3bb3208f59626a4b0ea6e526ee51f5a8ad5d91821c165903e8d9260", size = 2449023, upload-time = "2026-03-13T13:54:01.642Z" }, + { url = "https://files.pythonhosted.org/packages/b2/10/a800fa090b5e8819942e54e19b55fc7c21fe14a08757c3aa3ca8db358939/fonttools-4.62.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee91628c08e76f77b533d65feb3fbe6d9dad699f95be51cf0d022db94089cdc4", size = 5137599, upload-time = "2026-03-13T13:54:04.495Z" }, + { url = "https://files.pythonhosted.org/packages/37/dc/8ccd45033fffd74deb6912fa1ca524643f584b94c87a16036855b498a1ed/fonttools-4.62.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f37df1cac61d906e7b836abe356bc2f34c99d4477467755c216b72aa3dc748b", size = 4920933, upload-time = "2026-03-13T13:54:07.557Z" }, + { url = "https://files.pythonhosted.org/packages/99/eb/e618adefb839598d25ac8136cd577925d6c513dc0d931d93b8af956210f0/fonttools-4.62.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:92bb00a947e666169c99b43753c4305fc95a890a60ef3aeb2a6963e07902cc87", size = 5016232, upload-time = "2026-03-13T13:54:10.611Z" }, + { url = "https://files.pythonhosted.org/packages/d9/5f/9b5c9bfaa8ec82def8d8168c4f13615990d6ce5996fe52bd49bfb5e05134/fonttools-4.62.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:bdfe592802ef939a0e33106ea4a318eeb17822c7ee168c290273cbd5fabd746c", size = 5042987, upload-time = "2026-03-13T13:54:13.569Z" }, + { url = "https://files.pythonhosted.org/packages/90/aa/dfbbe24c6a6afc5c203d90cc0343e24bcbb09e76d67c4d6eef8c2558d7ba/fonttools-4.62.1-cp314-cp314t-win32.whl", hash = "sha256:b820fcb92d4655513d8402d5b219f94481c4443d825b4372c75a2072aa4b357a", size = 2348021, upload-time = "2026-03-13T13:54:16.98Z" }, + { url = "https://files.pythonhosted.org/packages/13/6f/ae9c4e4dd417948407b680855c2c7790efb52add6009aaecff1e3bc50e8e/fonttools-4.62.1-cp314-cp314t-win_amd64.whl", hash = "sha256:59b372b4f0e113d3746b88985f1c796e7bf830dd54b28374cd85c2b8acd7583e", size = 2414147, upload-time = "2026-03-13T13:54:19.416Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ba/56147c165442cc5ba7e82ecf301c9a68353cede498185869e6e02b4c264f/fonttools-4.62.1-py3-none-any.whl", hash = "sha256:7487782e2113861f4ddcc07c3436450659e3caa5e470b27dc2177cade2d8e7fd", size = 1152647, upload-time = "2026-03-13T13:54:22.735Z" }, ] [[package]] @@ -584,7 +710,7 @@ wheels = [ [[package]] name = "gevent" -version = "25.9.1" +version = "26.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation == 'CPython' and sys_platform == 'win32'" }, @@ -592,32 +718,32 @@ dependencies = [ { name = "zope-event" }, { name = "zope-interface" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/48/b3ef2673ffb940f980966694e40d6d32560f3ffa284ecaeb5ea3a90a6d3f/gevent-25.9.1.tar.gz", hash = "sha256:adf9cd552de44a4e6754c51ff2e78d9193b7fa6eab123db9578a210e657235dd", size = 5059025, upload-time = "2025-09-17T16:15:34.528Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/49/e55930ba5259629eb28ac7ee1abbca971996a9165f902f0249b561602f24/gevent-25.9.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:46b188248c84ffdec18a686fcac5dbb32365d76912e14fda350db5dc0bfd4f86", size = 2955991, upload-time = "2025-09-17T14:52:30.568Z" }, - { url = "https://files.pythonhosted.org/packages/aa/88/63dc9e903980e1da1e16541ec5c70f2b224ec0a8e34088cb42794f1c7f52/gevent-25.9.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f2b54ea3ca6f0c763281cd3f96010ac7e98c2e267feb1221b5a26e2ca0b9a692", size = 1808503, upload-time = "2025-09-17T15:41:25.59Z" }, - { url = "https://files.pythonhosted.org/packages/7a/8d/7236c3a8f6ef7e94c22e658397009596fa90f24c7d19da11ad7ab3a9248e/gevent-25.9.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7a834804ac00ed8a92a69d3826342c677be651b1c3cd66cc35df8bc711057aa2", size = 1890001, upload-time = "2025-09-17T15:49:01.227Z" }, - { url = "https://files.pythonhosted.org/packages/4f/63/0d7f38c4a2085ecce26b50492fc6161aa67250d381e26d6a7322c309b00f/gevent-25.9.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:323a27192ec4da6b22a9e51c3d9d896ff20bc53fdc9e45e56eaab76d1c39dd74", size = 1855335, upload-time = "2025-09-17T15:49:20.582Z" }, - { url = "https://files.pythonhosted.org/packages/95/18/da5211dfc54c7a57e7432fd9a6ffeae1ce36fe5a313fa782b1c96529ea3d/gevent-25.9.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6ea78b39a2c51d47ff0f130f4c755a9a4bbb2dd9721149420ad4712743911a51", size = 2109046, upload-time = "2025-09-17T15:15:13.817Z" }, - { url = "https://files.pythonhosted.org/packages/a6/5a/7bb5ec8e43a2c6444853c4a9f955f3e72f479d7c24ea86c95fb264a2de65/gevent-25.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:dc45cd3e1cc07514a419960af932a62eb8515552ed004e56755e4bf20bad30c5", size = 1827099, upload-time = "2025-09-17T15:52:41.384Z" }, - { url = "https://files.pythonhosted.org/packages/ca/d4/b63a0a60635470d7d986ef19897e893c15326dd69e8fb342c76a4f07fe9e/gevent-25.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34e01e50c71eaf67e92c186ee0196a039d6e4f4b35670396baed4a2d8f1b347f", size = 2172623, upload-time = "2025-09-17T15:24:12.03Z" }, - { url = "https://files.pythonhosted.org/packages/d5/98/caf06d5d22a7c129c1fb2fc1477306902a2c8ddfd399cd26bbbd4caf2141/gevent-25.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:4acd6bcd5feabf22c7c5174bd3b9535ee9f088d2bbce789f740ad8d6554b18f3", size = 1682837, upload-time = "2025-09-17T19:48:47.318Z" }, - { url = "https://files.pythonhosted.org/packages/5a/77/b97f086388f87f8ad3e01364f845004aef0123d4430241c7c9b1f9bde742/gevent-25.9.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:4f84591d13845ee31c13f44bdf6bd6c3dbf385b5af98b2f25ec328213775f2ed", size = 2973739, upload-time = "2025-09-17T14:53:30.279Z" }, - { url = "https://files.pythonhosted.org/packages/3c/2e/9d5f204ead343e5b27bbb2fedaec7cd0009d50696b2266f590ae845d0331/gevent-25.9.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9cdbb24c276a2d0110ad5c978e49daf620b153719ac8a548ce1250a7eb1b9245", size = 1809165, upload-time = "2025-09-17T15:41:27.193Z" }, - { url = "https://files.pythonhosted.org/packages/10/3e/791d1bf1eb47748606d5f2c2aa66571f474d63e0176228b1f1fd7b77ab37/gevent-25.9.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:88b6c07169468af631dcf0fdd3658f9246d6822cc51461d43f7c44f28b0abb82", size = 1890638, upload-time = "2025-09-17T15:49:02.45Z" }, - { url = "https://files.pythonhosted.org/packages/f2/5c/9ad0229b2b4d81249ca41e4f91dd8057deaa0da6d4fbe40bf13cdc5f7a47/gevent-25.9.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b7bb0e29a7b3e6ca9bed2394aa820244069982c36dc30b70eb1004dd67851a48", size = 1857118, upload-time = "2025-09-17T15:49:22.125Z" }, - { url = "https://files.pythonhosted.org/packages/49/2a/3010ed6c44179a3a5c5c152e6de43a30ff8bc2c8de3115ad8733533a018f/gevent-25.9.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2951bb070c0ee37b632ac9134e4fdaad70d2e660c931bb792983a0837fe5b7d7", size = 2111598, upload-time = "2025-09-17T15:15:15.226Z" }, - { url = "https://files.pythonhosted.org/packages/08/75/6bbe57c19a7aa4527cc0f9afcdf5a5f2aed2603b08aadbccb5bf7f607ff4/gevent-25.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e4e17c2d57e9a42e25f2a73d297b22b60b2470a74be5a515b36c984e1a246d47", size = 1829059, upload-time = "2025-09-17T15:52:42.596Z" }, - { url = "https://files.pythonhosted.org/packages/06/6e/19a9bee9092be45679cb69e4dd2e0bf5f897b7140b4b39c57cc123d24829/gevent-25.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d94936f8f8b23d9de2251798fcb603b84f083fdf0d7f427183c1828fb64f117", size = 2173529, upload-time = "2025-09-17T15:24:13.897Z" }, - { url = "https://files.pythonhosted.org/packages/ca/4f/50de9afd879440e25737e63f5ba6ee764b75a3abe17376496ab57f432546/gevent-25.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:eb51c5f9537b07da673258b4832f6635014fee31690c3f0944d34741b69f92fa", size = 1681518, upload-time = "2025-09-17T19:39:47.488Z" }, - { url = "https://files.pythonhosted.org/packages/15/1a/948f8167b2cdce573cf01cec07afc64d0456dc134b07900b26ac7018b37e/gevent-25.9.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:1a3fe4ea1c312dbf6b375b416925036fe79a40054e6bf6248ee46526ea628be1", size = 2982934, upload-time = "2025-09-17T14:54:11.302Z" }, - { url = "https://files.pythonhosted.org/packages/9b/ec/726b146d1d3aad82e03d2e1e1507048ab6072f906e83f97f40667866e582/gevent-25.9.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0adb937f13e5fb90cca2edf66d8d7e99d62a299687400ce2edee3f3504009356", size = 1813982, upload-time = "2025-09-17T15:41:28.506Z" }, - { url = "https://files.pythonhosted.org/packages/35/5d/5f83f17162301662bd1ce702f8a736a8a8cac7b7a35e1d8b9866938d1f9d/gevent-25.9.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:427f869a2050a4202d93cf7fd6ab5cffb06d3e9113c10c967b6e2a0d45237cb8", size = 1894902, upload-time = "2025-09-17T15:49:03.702Z" }, - { url = "https://files.pythonhosted.org/packages/83/cd/cf5e74e353f60dab357829069ffc300a7bb414c761f52cf8c0c6e9728b8d/gevent-25.9.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c049880175e8c93124188f9d926af0a62826a3b81aa6d3074928345f8238279e", size = 1861792, upload-time = "2025-09-17T15:49:23.279Z" }, - { url = "https://files.pythonhosted.org/packages/dd/65/b9a4526d4a4edce26fe4b3b993914ec9dc64baabad625a3101e51adb17f3/gevent-25.9.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b5a67a0974ad9f24721034d1e008856111e0535f1541499f72a733a73d658d1c", size = 2113215, upload-time = "2025-09-17T15:15:16.34Z" }, - { url = "https://files.pythonhosted.org/packages/e5/be/7d35731dfaf8370795b606e515d964a0967e129db76ea7873f552045dd39/gevent-25.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1d0f5d8d73f97e24ea8d24d8be0f51e0cf7c54b8021c1fddb580bf239474690f", size = 1833449, upload-time = "2025-09-17T15:52:43.75Z" }, - { url = "https://files.pythonhosted.org/packages/65/58/7bc52544ea5e63af88c4a26c90776feb42551b7555a1c89c20069c168a3f/gevent-25.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ddd3ff26e5c4240d3fbf5516c2d9d5f2a998ef87cfb73e1429cfaeaaec860fa6", size = 2176034, upload-time = "2025-09-17T15:24:15.676Z" }, - { url = "https://files.pythonhosted.org/packages/c2/69/a7c4ba2ffbc7c7dbf6d8b4f5d0f0a421f7815d229f4909854266c445a3d4/gevent-25.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:bb63c0d6cb9950cc94036a4995b9cc4667b8915366613449236970f4394f94d7", size = 1703019, upload-time = "2025-09-17T19:30:55.272Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/20/27/1062fa31333dc3428a1f5f33cd6598b0552165ba679ca3ba116de42c9e8e/gevent-26.4.0.tar.gz", hash = "sha256:288d03addfccf0d1c67268358b6759b04392bf3bc35d26f3d9a45c82899c292d", size = 6242440, upload-time = "2026-04-09T12:08:19.482Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/16/131d3874f50974b355c90a061a12d3fe2292cde0f875a1fa3d8b224f1251/gevent-26.4.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:318a0a73f664113e8d86d0cb0e328e7650e2d7d9c2e045418ab6fb1285831ad3", size = 2928699, upload-time = "2026-04-08T21:25:36.215Z" }, + { url = "https://files.pythonhosted.org/packages/ea/8b/199e59b303adaff7f7365def9ab569c7ecd863363c974548bce3ddc2c89d/gevent-26.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:ce7aa033a3f68beb6732d1450a80c1af29e63e0c2d01abad7918cf2507f72fa6", size = 1783821, upload-time = "2026-04-08T22:23:18.73Z" }, + { url = "https://files.pythonhosted.org/packages/e2/2d/b8249c9bd3f386191311c3a9bec4068e192a3f9df2fad92a71a15265ba15/gevent-26.4.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:a1b897c952baefd72232efaeb3bdb1ca2fa7ae94cbfe68ac21201b03e843190a", size = 1879424, upload-time = "2026-04-08T22:27:10.561Z" }, + { url = "https://files.pythonhosted.org/packages/ef/89/59216985c1f2c11f2f28bbc88e583588ad44cdde823c530ad4e307be6612/gevent-26.4.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:7eef2ea508ce41795e20587a5fc868ae4919543097c81a40fbdfd65bc479f54f", size = 1830575, upload-time = "2026-04-08T22:34:37.093Z" }, + { url = "https://files.pythonhosted.org/packages/ee/a9/2d67d2b0aa0ca9d7bb7fe73c3bbb97b3695cb15c338a6ea7734f58da9add/gevent-26.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:f7e12fdd28cc9f39a463d8df5172d698c64a8ed385a21d98e7092fd8308a139a", size = 2113898, upload-time = "2026-04-08T21:54:14.9Z" }, + { url = "https://files.pythonhosted.org/packages/95/a3/457d58d9b3e7da17c8456d841c37a32af8d231a1d71237ad201b19129317/gevent-26.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d48e3ee13d7678c24c22f19d441ad6bc220a79f23662d03ff36fae0d62efdb59", size = 1795890, upload-time = "2026-04-08T22:26:53.252Z" }, + { url = "https://files.pythonhosted.org/packages/a7/cc/cbe78f2626643b20275aaa41cd2cc45ba75056e3665bde36bc190af3cae0/gevent-26.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c58c8e034f94329be4dc0979fba3301005a433dbab42cea0b2c33fd736946872", size = 2139791, upload-time = "2026-04-08T22:00:02.375Z" }, + { url = "https://files.pythonhosted.org/packages/f6/df/7875e08b06a95f4577b71708ec470d029fadf873a66eb813a2861d79dfb5/gevent-26.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1c737e6ac6ce1398df0e3f41c58d982e397c993cbe73ac05b7edbe39e128c9cb", size = 1680530, upload-time = "2026-04-08T23:15:38.714Z" }, + { url = "https://files.pythonhosted.org/packages/3d/be/51809d98bb00846d7756a0b82625024f9302145f3d024846b43f05efeddb/gevent-26.4.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1fe581d41c63cd1d8b12c69561ce53a48ad0d8763b254740d7bfea997335a38c", size = 2951507, upload-time = "2026-04-08T21:25:25.809Z" }, + { url = "https://files.pythonhosted.org/packages/d6/86/89325a62a4e8cc1934e155b383b66491ed21d1e774b13d5054d51fa0ac81/gevent-26.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c503b0c0a681e795255a13e5bb4e41615c3b020c1db93b8dfa04cfeb8f19d5a9", size = 1786029, upload-time = "2026-04-08T22:23:20.395Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ea/04d112844aa992da583cbd280f17a4ba097da338dab347efd0aa5e235645/gevent-26.4.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:684256c29e3e5d4d0c4d06b772d00574d0dc859dfbb2fd13d318c512b16e1f89", size = 1881326, upload-time = "2026-04-08T22:27:11.822Z" }, + { url = "https://files.pythonhosted.org/packages/a1/33/71900c5ba442f5df89456b6d9fdaa43da2ae7cdd937d8c5667b49323ceb4/gevent-26.4.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:73eafd06b158d511f1ec6e5902a45e0ae3b48e745f35e9df97d25f809f537d88", size = 1833123, upload-time = "2026-04-08T22:34:39.001Z" }, + { url = "https://files.pythonhosted.org/packages/d0/af/7df19c92e56842921f34787e1168c7afc52a23b0d1253bba99344809a935/gevent-26.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1a18e543c830a1c07a2efeb33786a57ccac360af70cb42bbaf5a6f5f7ca49300", size = 2114330, upload-time = "2026-04-08T21:54:16.547Z" }, + { url = "https://files.pythonhosted.org/packages/ca/0e/202694960f8d4dda68fd2a73bbcb8251e2d5308339924310ff1fff31bf7c/gevent-26.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:74f1e3a460c43aefcb4ff9ef91aac15abc0b42e5233771e1956574d14ba9cac6", size = 1798427, upload-time = "2026-04-08T22:26:54.462Z" }, + { url = "https://files.pythonhosted.org/packages/75/69/2d056b2a4e3ef1f65f94002725572d1e99163ff79231dbb68ad529e7cb9d/gevent-26.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:954258873ae0bcc97fb41e48db25284fb73454bfefe27db8ceb89225da5502fb", size = 2140100, upload-time = "2026-04-08T22:00:03.966Z" }, + { url = "https://files.pythonhosted.org/packages/fe/a0/1a7f64aa2476c2b44abaecca919a6561bda85234f99fc7ac3c66bcb93050/gevent-26.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:4a9a64c064457c1afaf93ee2815fe0f38be6ecbb92806a6a712f12afc3e26cf5", size = 1680206, upload-time = "2026-04-08T23:01:56.636Z" }, + { url = "https://files.pythonhosted.org/packages/7e/f3/64638a941988f09aa1816e2674eb1efb215b6fa64a97edef6e25177b0845/gevent-26.4.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:7ab0f183a6fd2369eef619832eef14f1f2f69c605163c3f2dc41deb799af4a71", size = 2967206, upload-time = "2026-04-08T21:25:44.73Z" }, + { url = "https://files.pythonhosted.org/packages/f6/70/a86be65a51d3ebb92c82a70adc9c5c32b1a9d9579120d0be1db7cf534ce0/gevent-26.4.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:7e5906860e632bf965e1966c57e6bfc19dcb79dc262f04fdb0a9d7c12147bf69", size = 1792916, upload-time = "2026-04-08T22:23:22.006Z" }, + { url = "https://files.pythonhosted.org/packages/40/92/18fdb4b28f20129395f1c041773adee99e7fc2bcfff216df93bfb80787d5/gevent-26.4.0-cp314-cp314-manylinux_2_28_ppc64le.whl", hash = "sha256:297a361071dc6708115d4544859321e93b02a6cd5823ba02c0a909530a519d45", size = 1886617, upload-time = "2026-04-08T22:27:13.716Z" }, + { url = "https://files.pythonhosted.org/packages/af/c9/d02222ecf79d10c8a0c2755661485395b58c4bfffaafd88bcc230ce392de/gevent-26.4.0-cp314-cp314-manylinux_2_28_s390x.whl", hash = "sha256:7e74f59e5c9011afa2a9cb7106bb9a59f2a1f74c3d7b272c1b852eb0bc0b8f90", size = 1837660, upload-time = "2026-04-08T22:34:40.823Z" }, + { url = "https://files.pythonhosted.org/packages/46/85/9376d125fa4f7b0f269925d0d622eda0ff8f8dfc8d0c097a096c511fc738/gevent-26.4.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:45d6010a6a981f5a2b3411c4e38fbe305a1b46e4b12db3b4914775927dea7ba4", size = 2119342, upload-time = "2026-04-08T21:54:17.747Z" }, + { url = "https://files.pythonhosted.org/packages/b1/c4/1fe2817daca8e97c365fd739dd4057f71cce26ef600fb8465deb8060c83c/gevent-26.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:dc38137ba2f43794c488615aafa2eefd0cc142f484a8274d4c827ed7a031a1e2", size = 1805672, upload-time = "2026-04-08T22:26:55.792Z" }, + { url = "https://files.pythonhosted.org/packages/e7/cc/ccbcbd56e7e85482291fbb90a317f5febf630ec4174a91506f4167ba0912/gevent-26.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:29a225d2d4da37e20c7a246754a64442d0e43e4534b8cc764f89530bb22a4237", size = 2145594, upload-time = "2026-04-08T22:00:05.275Z" }, + { url = "https://files.pythonhosted.org/packages/8e/b9/7dd37b6001d16f692b1bfb6e68cad642beb38b34a753c29bbff312f46e4b/gevent-26.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:d1c08bc9bb6bd79732a26710a99588b5e9b67b668e165dd609704b876f41baab", size = 1703189, upload-time = "2026-04-08T22:48:31.713Z" }, ] [[package]] @@ -644,65 +770,219 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/09/e21df6aef1e1ffc0c816f0522ddc3f6dcded766c3261813131c78a704470/gitpython-3.1.46-py3-none-any.whl", hash = "sha256:79812ed143d9d25b6d176a10bb511de0f9c67b1fa641d82097b0ab90398a2058", size = 208620, upload-time = "2026-01-01T15:37:30.574Z" }, ] +[[package]] +name = "glfw" +version = "2.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/72/642d4f12f61816ac96777f7360d413e3977a7dd08237d196f02da681b186/glfw-2.10.0.tar.gz", hash = "sha256:801e55d8581b34df9aa2cfea43feb06ff617576e2a8cc5dac23ee75b26d10abe", size = 31475, upload-time = "2025-09-12T08:54:38.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/1f/a9ce08b1173b0ab625ee92f0c47a5278b3e76fd367699880d8ee7d56c338/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-macosx_10_6_intel.whl", hash = "sha256:5f365a8c94bcea71ec91327e7c16e7cf739128479a18b8c1241b004b40acc412", size = 105329, upload-time = "2025-09-12T08:54:27.938Z" }, + { url = "https://files.pythonhosted.org/packages/7c/96/5a2220abcbd027eebcf8bedd28207a2de168899e51be13ba01ebdd4147a1/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-macosx_11_0_arm64.whl", hash = "sha256:5328db1a92d07abd988730517ec02aa8390d3e6ef7ce98c8b57ecba2f43a39ba", size = 102179, upload-time = "2025-09-12T08:54:29.163Z" }, + { url = "https://files.pythonhosted.org/packages/9d/41/a5bd1d9e1808f400102bd7d328c4ac17b65fb2fc8014014ec6f23d02f662/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-manylinux2014_aarch64.whl", hash = "sha256:312c4c1dd5509613ed6bc1e95a8dbb75a36b6dcc4120f50dc3892b40172e9053", size = 230039, upload-time = "2025-09-12T08:54:30.201Z" }, + { url = "https://files.pythonhosted.org/packages/80/aa/3b503c448609dee6cb4e7138b4109338f0e65b97be107ab85562269d378d/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-manylinux2014_x86_64.whl", hash = "sha256:59c53387dc08c62e8bed86bbe3a8d53ab1b27161281ffa0e7f27b64284e2627c", size = 241984, upload-time = "2025-09-12T08:54:31.347Z" }, + { url = "https://files.pythonhosted.org/packages/ac/2d/bfe39a42cad8e80b02bf5f7cae19ba67832c1810bbd3624a8e83153d74a4/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-manylinux_2_28_aarch64.whl", hash = "sha256:c6f292fdaf3f9a99e598ede6582d21c523a6f51f8f5e66213849101a6bcdc699", size = 231052, upload-time = "2025-09-12T08:54:32.859Z" }, + { url = "https://files.pythonhosted.org/packages/f7/02/6e639e90f181dc9127046e00d0528f9f7ad12d428972e3a5378b9aefdb0b/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-manylinux_2_28_x86_64.whl", hash = "sha256:7916034efa867927892635733a3b6af8cd95ceb10566fd7f1e0d2763c2ee8b12", size = 243525, upload-time = "2025-09-12T08:54:34.006Z" }, + { url = "https://files.pythonhosted.org/packages/84/06/cb588ca65561defe0fc48d1df4c2ac12569b81231ae4f2b52ab37007d0bd/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-win32.whl", hash = "sha256:6c9549da71b93e367b4d71438798daae1da2592039fd14204a80a1a2348ae127", size = 552685, upload-time = "2025-09-12T08:54:35.723Z" }, + { url = "https://files.pythonhosted.org/packages/86/27/00c9c96af18ac0a5eac2ff61cbe306551a2d770d7173f396d0792ee1a59e/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.p39.p310.p311.p312.p313-none-win_amd64.whl", hash = "sha256:6292d5d6634d668cd23d337e6089491d3945a9aa4ac6e1667b0003520d7caa51", size = 559466, upload-time = "2025-09-12T08:54:37.661Z" }, + { url = "https://files.pythonhosted.org/packages/b3/87/de0b33f6f00687499ca1371f22aa73396341b85bf88f1a284f9da8842493/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.py39.py310.py311.py312.py313.py314-none-macosx_10_6_intel.whl", hash = "sha256:2aab89d2d9535635ba011fc7303390685169a1aa6731ad580d08d043524b8899", size = 105326, upload-time = "2026-01-28T05:57:56.083Z" }, + { url = "https://files.pythonhosted.org/packages/b6/a6/6ea2f73ad4474896d9e38b3ffbe6ffd5a802c738392269e99e8c6621a461/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.py39.py310.py311.py312.py313.py314-none-macosx_11_0_arm64.whl", hash = "sha256:23936202a107039b5372f0b88ae1d11080746aa1c78910a45d4a0c4cf408cfaa", size = 102180, upload-time = "2026-01-28T05:57:57.787Z" }, + { url = "https://files.pythonhosted.org/packages/58/19/d81b19e8261b9cb51b81d1402167791fef81088dfe91f0c4e9d136fdc5ca/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.py39.py310.py311.py312.py313.py314-none-manylinux2014_aarch64.whl", hash = "sha256:7be06d0838f61df67bd54cb6266a6193d54083acb3624ff3c3812a6358406fa4", size = 230038, upload-time = "2026-01-28T05:57:59.105Z" }, + { url = "https://files.pythonhosted.org/packages/e2/fa/b035636cd82198b97b51a93efe9cfc4343d6b15cefbd336a3f2be871d848/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.py39.py310.py311.py312.py313.py314-none-manylinux2014_x86_64.whl", hash = "sha256:91d36b3582a766512eff8e3b5dcc2d3ffcbf10b7cf448551085a08a10f1b8244", size = 241983, upload-time = "2026-01-28T05:58:00.352Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b4/f7b6cc022dd7c68b6c702d19da5d591f978f89c958b9bd3090615db0c739/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.py39.py310.py311.py312.py313.py314-none-manylinux_2_28_aarch64.whl", hash = "sha256:27c9e9a2d5e1dc3c9e3996171d844d9df9a5a101e797cb94cce217b7afcf8fd9", size = 231053, upload-time = "2026-01-28T05:58:01.683Z" }, + { url = "https://files.pythonhosted.org/packages/5a/3f/efeb7c6801c46e11bd666a5180f0d615f74f72264212f74f39586c6fda9d/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.py39.py310.py311.py312.py313.py314-none-manylinux_2_28_x86_64.whl", hash = "sha256:ce6724bb7cb3d0543dcba17206dce909f94176e68220b8eafee72e9f92bcf542", size = 243522, upload-time = "2026-01-28T05:58:03.517Z" }, + { url = "https://files.pythonhosted.org/packages/cf/b9/b04c3aa0aad2870cfe799f32f8b59789c98e1816bbce9e83f4823c5b840b/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.py39.py310.py311.py312.py313.py314-none-win32.whl", hash = "sha256:fca724a21a372731edb290841edd28a9fb1ee490f833392752844ac807c0086a", size = 552682, upload-time = "2026-01-28T05:58:05.649Z" }, + { url = "https://files.pythonhosted.org/packages/bd/e1/6d6816b296a529ac9b897ad228b1e084eb1f92319e96371880eebdc874a6/glfw-2.10.0-py2.py27.py3.py30.py31.py32.py33.py34.py35.py36.py37.py38.py39.py310.py311.py312.py313.py314-none-win_amd64.whl", hash = "sha256:823c0bd7770977d4b10e0ed0aef2f3682276b7c88b8b65cfc540afce5951392f", size = 559464, upload-time = "2026-01-28T05:58:07.261Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a8/d4dab8a58fc2e6981fc7a58c4e56ba9d777fb24931cec6a22152edbb3540/glfw-2.10.0-py2.py3-none-macosx_10_6_intel.whl", hash = "sha256:a0d1f29f206219cc291edfb6cace663a86da2470632551c998e3db82d48ea177", size = 105288, upload-time = "2026-03-10T17:21:19.929Z" }, + { url = "https://files.pythonhosted.org/packages/14/61/68d35e001872a7705112418da236fa2418d4f2e5419f8b2837f9b81bb3da/glfw-2.10.0-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:d28d6f3ef217e64e35dc6fd0a7acb4cec9bfe7cd14dd9b35a7228a87002de154", size = 102139, upload-time = "2026-03-10T17:21:21.645Z" }, + { url = "https://files.pythonhosted.org/packages/4e/e1/ca5984081aaae07c9d371cb11dc4e4ff603510678ed9b73e58b6c351fe63/glfw-2.10.0-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:f968b522bb6a0e04aaf4dcac30a476d7229308bb2bac406a60587debb5a61e29", size = 229998, upload-time = "2026-03-10T17:21:23.549Z" }, + { url = "https://files.pythonhosted.org/packages/fa/c4/82ac75fdcfba2896da7a573c0fc7f8ceb8f77ead6866d500d06c32f1c464/glfw-2.10.0-py2.py3-none-manylinux2014_x86_64.whl", hash = "sha256:68cf3752bdadb6f4bc0a876247c28c88c7251ac39f8af076ed938fdfd71e72dd", size = 241944, upload-time = "2026-03-10T17:21:26.102Z" }, + { url = "https://files.pythonhosted.org/packages/e3/96/9f691823cca5eb6a08f346bd0ff03b78032db9370b509a1e9c8976fb20a5/glfw-2.10.0-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:44d98de5dbf8f727e0cb29f9b29d29528ea7570f2e6f42f8430a69df05f12b48", size = 231009, upload-time = "2026-03-10T17:21:28.481Z" }, + { url = "https://files.pythonhosted.org/packages/3f/93/977b9e679e356871d428ae7a1139ec767dd5177bed58a6344b4d2199e00f/glfw-2.10.0-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:cca5158d62189e08792b1ae54f92307a282921a0e7783315b467e21b0a381c88", size = 243480, upload-time = "2026-03-10T17:21:30.538Z" }, + { url = "https://files.pythonhosted.org/packages/f9/bd/cea9569c8f2188b0a104472951420434a3e1f5cf26f5836ef9d7227a1a30/glfw-2.10.0-py2.py3-none-win32.whl", hash = "sha256:5e024509989740e8e7b86cc4aab508195495f79879072b0e1f68bd036a2916ad", size = 552641, upload-time = "2026-03-10T17:21:32.653Z" }, + { url = "https://files.pythonhosted.org/packages/cc/9b/4366ad3e1c0688146c70aa6143584d6a8d88583b9390f106250e25a3d5cd/glfw-2.10.0-py2.py3-none-win_amd64.whl", hash = "sha256:7f787ee8645781f10e8800438ce4357ab38c573ffb191aba380c1e72eba6311c", size = 559423, upload-time = "2026-03-10T17:21:34.766Z" }, +] + +[[package]] +name = "google-api-core" +version = "2.30.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth" }, + { name = "googleapis-common-protos" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/16/ce/502a57fb0ec752026d24df1280b162294b22a0afb98a326084f9a979138b/google_api_core-2.30.3.tar.gz", hash = "sha256:e601a37f148585319b26db36e219df68c5d07b6382cff2d580e83404e44d641b", size = 177001, upload-time = "2026-04-10T00:41:28.035Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/15/e56f351cf6ef1cfea58e6ac226a7318ed1deb2218c4b3cc9bd9e4b786c5a/google_api_core-2.30.3-py3-none-any.whl", hash = "sha256:a85761ba72c444dad5d611c2220633480b2b6be2521eca69cca2dbb3ffd6bfe8", size = 173274, upload-time = "2026-04-09T22:57:16.198Z" }, +] + +[package.optional-dependencies] +grpc = [ + { name = "grpcio" }, + { name = "grpcio-status" }, +] + +[[package]] +name = "google-auth" +version = "2.49.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "pyasn1-modules" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c6/fc/e925290a1ad95c975c459e2df070fac2b90954e13a0370ac505dff78cb99/google_auth-2.49.2.tar.gz", hash = "sha256:c1ae38500e73065dcae57355adb6278cf8b5c8e391994ae9cbadbcb9631ab409", size = 333958, upload-time = "2026-04-10T00:41:21.888Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/76/d241a5c927433420507215df6cac1b1fa4ac0ba7a794df42a84326c68da8/google_auth-2.49.2-py3-none-any.whl", hash = "sha256:c2720924dfc82dedb962c9f52cabb2ab16714fd0a6a707e40561d217574ed6d5", size = 240638, upload-time = "2026-04-10T00:41:14.501Z" }, +] + +[[package]] +name = "google-cloud" +version = "0.34.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/0e/8bf108fa9e3e036fe37a86598f1315e7b8de90b89012fd65704dc30ac6ad/google-cloud-0.34.0.tar.gz", hash = "sha256:01430187cf56df10a9ba775dd547393185d4b40741db0ea5889301f8e7a9d5d3", size = 2514, upload-time = "2018-07-30T19:08:17.761Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/b1/7c54d1950e7808df06642274e677dbcedba57f75307adf2e5ad8d39e5e0e/google_cloud-0.34.0-py2.py3-none-any.whl", hash = "sha256:fb1ab7b0548fe44b3d538041f0a374505b7f990d448a935ea36649c5ccab5acf", size = 1839, upload-time = "2018-07-30T19:08:16.739Z" }, +] + +[[package]] +name = "google-cloud-speech" +version = "2.38.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core", extra = ["grpc"] }, + { name = "google-auth" }, + { name = "grpcio" }, + { name = "proto-plus" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/1f/d0122ad8af8c0608fb3168bd5030e62ce0a1fcc09c730487bc8be541874a/google_cloud_speech-2.38.0.tar.gz", hash = "sha256:1854b51cbb7957273b6ba61f4a6cf49dec8d09ec450991587897e50267eaca51", size = 406015, upload-time = "2026-03-26T22:18:54.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/96/008365cddc78720d65475091be929466fb16c62b47283546f8eab5ff4445/google_cloud_speech-2.38.0-py3-none-any.whl", hash = "sha256:dbccb340a750a409b0e70c48c16c8d7d5d48a87c70cce2add50f3d571f5375a0", size = 346013, upload-time = "2026-03-26T22:13:50.88Z" }, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.74.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/18/a746c8344152d368a5aac738d4c857012f2c5d1fd2eac7e17b647a7861bd/googleapis_common_protos-1.74.0.tar.gz", hash = "sha256:57971e4eeeba6aad1163c1f0fc88543f965bb49129b8bb55b2b7b26ecab084f1", size = 151254, upload-time = "2026-04-02T21:23:26.679Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b6/b0/be5d3329badb9230b765de6eea66b73abd5944bdeb5afb3562ddcd80ae84/googleapis_common_protos-1.74.0-py3-none-any.whl", hash = "sha256:702216f78610bb510e3f12ac3cafd281b7ac45cc5d86e90ad87e4d301a3426b5", size = 300743, upload-time = "2026-04-02T21:22:49.108Z" }, +] + [[package]] name = "greenlet" -version = "3.3.2" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/86/94/a5935717b307d7c71fe877b52b884c6af707d2d2090db118a03fbd799369/greenlet-3.4.0.tar.gz", hash = "sha256:f50a96b64dafd6169e595a5c56c9146ef80333e67d4476a65a9c55f400fc22ff", size = 195913, upload-time = "2026-04-08T17:08:00.863Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/8b/3669ad3b3f247a791b2b4aceb3aa5a31f5f6817bf547e4e1ff712338145a/greenlet-3.4.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:1a54a921561dd9518d31d2d3db4d7f80e589083063ab4d3e2e950756ef809e1a", size = 286902, upload-time = "2026-04-08T15:52:12.138Z" }, + { url = "https://files.pythonhosted.org/packages/38/3e/3c0e19b82900873e2d8469b590a6c4b3dfd2b316d0591f1c26b38a4879a5/greenlet-3.4.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16dec271460a9a2b154e3b1c2fa1050ce6280878430320e85e08c166772e3f97", size = 606099, upload-time = "2026-04-08T16:24:38.408Z" }, + { url = "https://files.pythonhosted.org/packages/b5/33/99fef65e7754fc76a4ed14794074c38c9ed3394a5bd129d7f61b705f3168/greenlet-3.4.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90036ce224ed6fe75508c1907a77e4540176dcf0744473627785dd519c6f9996", size = 618837, upload-time = "2026-04-08T16:30:58.298Z" }, + { url = "https://files.pythonhosted.org/packages/44/57/eae2cac10421feae6c0987e3dc106c6d86262b1cb379e171b017aba893a6/greenlet-3.4.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6f0def07ec9a71d72315cf26c061aceee53b306c36ed38c35caba952ea1b319d", size = 624901, upload-time = "2026-04-08T16:40:38.981Z" }, + { url = "https://files.pythonhosted.org/packages/36/f7/229f3aed6948faa20e0616a0b8568da22e365ede6a54d7d369058b128afd/greenlet-3.4.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a1c4f6b453006efb8310affb2d132832e9bbb4fc01ce6df6b70d810d38f1f6dc", size = 615062, upload-time = "2026-04-08T15:56:33.766Z" }, + { url = "https://files.pythonhosted.org/packages/6a/8a/0e73c9b94f31d1cc257fe79a0eff621674141cdae7d6d00f40de378a1e42/greenlet-3.4.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:0e1254cf0cbaa17b04320c3a78575f29f3c161ef38f59c977108f19ffddaf077", size = 423927, upload-time = "2026-04-08T16:43:05.293Z" }, + { url = "https://files.pythonhosted.org/packages/08/97/d988180011aa40135c46cd0d0cf01dd97f7162bae14139b4a3ef54889ba5/greenlet-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9b2d9a138ffa0e306d0e2b72976d2fb10b97e690d40ab36a472acaab0838e2de", size = 1573511, upload-time = "2026-04-08T16:26:20.058Z" }, + { url = "https://files.pythonhosted.org/packages/d4/0f/a5a26fe152fb3d12e6a474181f6e9848283504d0afd095f353d85726374b/greenlet-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8424683caf46eb0eb6f626cb95e008e8cc30d0cb675bdfa48200925c79b38a08", size = 1640396, upload-time = "2026-04-08T15:57:30.88Z" }, + { url = "https://files.pythonhosted.org/packages/42/cf/bb2c32d9a100e36ee9f6e38fad6b1e082b8184010cb06259b49e1266ca01/greenlet-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0a53fb071531d003b075c444014ff8f8b1a9898d36bb88abd9ac7b3524648a2", size = 238892, upload-time = "2026-04-08T17:03:10.094Z" }, + { url = "https://files.pythonhosted.org/packages/b7/47/6c41314bac56e71436ce551c7fbe3cc830ed857e6aa9708dbb9c65142eb6/greenlet-3.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:f38b81880ba28f232f1f675893a39cf7b6db25b31cc0a09bb50787ecf957e85e", size = 235599, upload-time = "2026-04-08T15:52:54.3Z" }, + { url = "https://files.pythonhosted.org/packages/7a/75/7e9cd1126a1e1f0cd67b0eda02e5221b28488d352684704a78ed505bd719/greenlet-3.4.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:43748988b097f9c6f09364f260741aa73c80747f63389824435c7a50bfdfd5c1", size = 285856, upload-time = "2026-04-08T15:52:45.82Z" }, + { url = "https://files.pythonhosted.org/packages/9d/c4/3e2df392e5cb199527c4d9dbcaa75c14edcc394b45040f0189f649631e3c/greenlet-3.4.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5566e4e2cd7a880e8c27618e3eab20f3494452d12fd5129edef7b2f7aa9a36d1", size = 610208, upload-time = "2026-04-08T16:24:39.674Z" }, + { url = "https://files.pythonhosted.org/packages/da/af/750cdfda1d1bd30a6c28080245be8d0346e669a98fdbae7f4102aa95fff3/greenlet-3.4.0-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1054c5a3c78e2ab599d452f23f7adafef55062a783a8e241d24f3b633ba6ff82", size = 621269, upload-time = "2026-04-08T16:30:59.767Z" }, + { url = "https://files.pythonhosted.org/packages/e0/93/c8c508d68ba93232784bbc1b5474d92371f2897dfc6bc281b419f2e0d492/greenlet-3.4.0-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:98eedd1803353daf1cd9ef23eef23eda5a4d22f99b1f998d273a8b78b70dd47f", size = 628455, upload-time = "2026-04-08T16:40:40.698Z" }, + { url = "https://files.pythonhosted.org/packages/54/78/0cbc693622cd54ebe25207efbb3a0eb07c2639cb8594f6e3aaaa0bb077a8/greenlet-3.4.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f82cb6cddc27dd81c96b1506f4aa7def15070c3b2a67d4e46fd19016aacce6cf", size = 617549, upload-time = "2026-04-08T15:56:34.893Z" }, + { url = "https://files.pythonhosted.org/packages/7f/46/cfaaa0ade435a60550fd83d07dfd5c41f873a01da17ede5c4cade0b9bab8/greenlet-3.4.0-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:b7857e2202aae67bc5725e0c1f6403c20a8ff46094ece015e7d474f5f7020b55", size = 426238, upload-time = "2026-04-08T16:43:06.865Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c0/8966767de01343c1ff47e8b855dc78e7d1a8ed2b7b9c83576a57e289f81d/greenlet-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:227a46251ecba4ff46ae742bc5ce95c91d5aceb4b02f885487aff269c127a729", size = 1575310, upload-time = "2026-04-08T16:26:21.671Z" }, + { url = "https://files.pythonhosted.org/packages/b8/38/bcdc71ba05e9a5fda87f63ffc2abcd1f15693b659346df994a48c968003d/greenlet-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5b99e87be7eba788dd5b75ba1cde5639edffdec5f91fe0d734a249535ec3408c", size = 1640435, upload-time = "2026-04-08T15:57:32.572Z" }, + { url = "https://files.pythonhosted.org/packages/a1/c2/19b664b7173b9e4ef5f77e8cef9f14c20ec7fce7920dc1ccd7afd955d093/greenlet-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:849f8bc17acd6295fcb5de8e46d55cc0e52381c56eaf50a2afd258e97bc65940", size = 238760, upload-time = "2026-04-08T17:04:03.878Z" }, + { url = "https://files.pythonhosted.org/packages/9b/96/795619651d39c7fbd809a522f881aa6f0ead504cc8201c3a5b789dfaef99/greenlet-3.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:9390ad88b652b1903814eaabd629ca184db15e0eeb6fe8a390bbf8b9106ae15a", size = 235498, upload-time = "2026-04-08T17:05:00.584Z" }, + { url = "https://files.pythonhosted.org/packages/78/02/bde66806e8f169cf90b14d02c500c44cdbe02c8e224c9c67bafd1b8cadd1/greenlet-3.4.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:10a07aca6babdd18c16a3f4f8880acfffc2b88dfe431ad6aa5f5740759d7d75e", size = 286291, upload-time = "2026-04-08T17:09:34.307Z" }, + { url = "https://files.pythonhosted.org/packages/05/1f/39da1c336a87d47c58352fb8a78541ce63d63ae57c5b9dae1fe02801bbc2/greenlet-3.4.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:076e21040b3a917d3ce4ad68fb5c3c6b32f1405616c4a57aa83120979649bd3d", size = 656749, upload-time = "2026-04-08T16:24:41.721Z" }, + { url = "https://files.pythonhosted.org/packages/d3/6c/90ee29a4ee27af7aa2e2ec408799eeb69ee3fcc5abcecac6ddd07a5cd0f2/greenlet-3.4.0-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e82689eea4a237e530bb5cb41b180ef81fa2160e1f89422a67be7d90da67f615", size = 669084, upload-time = "2026-04-08T16:31:01.372Z" }, + { url = "https://files.pythonhosted.org/packages/d2/4a/74078d3936712cff6d3c91a930016f476ce4198d84e224fe6d81d3e02880/greenlet-3.4.0-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:06c2d3b89e0c62ba50bd7adf491b14f39da9e7e701647cb7b9ff4c99bee04b19", size = 673405, upload-time = "2026-04-08T16:40:42.527Z" }, + { url = "https://files.pythonhosted.org/packages/07/49/d4cad6e5381a50947bb973d2f6cf6592621451b09368b8c20d9b8af49c5b/greenlet-3.4.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4df3b0b2289ec686d3c821a5fee44259c05cfe824dd5e6e12c8e5f5df23085cf", size = 665621, upload-time = "2026-04-08T15:56:35.995Z" }, + { url = "https://files.pythonhosted.org/packages/79/3e/df8a83ab894751bc31e1106fdfaa80ca9753222f106b04de93faaa55feb7/greenlet-3.4.0-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:070b8bac2ff3b4d9e0ff36a0d19e42103331d9737e8504747cd1e659f76297bd", size = 471670, upload-time = "2026-04-08T16:43:08.512Z" }, + { url = "https://files.pythonhosted.org/packages/37/31/d1edd54f424761b5d47718822f506b435b6aab2f3f93b465441143ea5119/greenlet-3.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8bff29d586ea415688f4cec96a591fcc3bf762d046a796cdadc1fdb6e7f2d5bf", size = 1622259, upload-time = "2026-04-08T16:26:23.201Z" }, + { url = "https://files.pythonhosted.org/packages/b0/c6/6d3f9cdcb21c4e12a79cb332579f1c6aa1af78eb68059c5a957c7812d95e/greenlet-3.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8a569c2fb840c53c13a2b8967c63621fafbd1a0e015b9c82f408c33d626a2fda", size = 1686916, upload-time = "2026-04-08T15:57:34.282Z" }, + { url = "https://files.pythonhosted.org/packages/63/45/c1ca4a1ad975de4727e52d3ffe641ae23e1d7a8ffaa8ff7a0477e1827b92/greenlet-3.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:207ba5b97ea8b0b60eb43ffcacf26969dd83726095161d676aac03ff913ee50d", size = 239821, upload-time = "2026-04-08T17:03:48.423Z" }, + { url = "https://files.pythonhosted.org/packages/71/c4/6f621023364d7e85a4769c014c8982f98053246d142420e0328980933ceb/greenlet-3.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:f8296d4e2b92af34ebde81085a01690f26a51eb9ac09a0fcadb331eb36dbc802", size = 236932, upload-time = "2026-04-08T17:04:33.551Z" }, + { url = "https://files.pythonhosted.org/packages/d4/8f/18d72b629783f5e8d045a76f5325c1e938e659a9e4da79c7dcd10169a48d/greenlet-3.4.0-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:d70012e51df2dbbccfaf63a40aaf9b40c8bed37c3e3a38751c926301ce538ece", size = 294681, upload-time = "2026-04-08T15:52:35.778Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ad/5fa86ec46769c4153820d58a04062285b3b9e10ba3d461ee257b68dcbf53/greenlet-3.4.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a58bec0751f43068cd40cff31bb3ca02ad6000b3a51ca81367af4eb5abc480c8", size = 658899, upload-time = "2026-04-08T16:24:43.32Z" }, + { url = "https://files.pythonhosted.org/packages/43/f0/4e8174ca0e87ae748c409f055a1ba161038c43cc0a5a6f1433a26ac2e5bf/greenlet-3.4.0-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:05fa0803561028f4b2e3b490ee41216a842eaee11aed004cc343a996d9523aa2", size = 665284, upload-time = "2026-04-08T16:31:02.833Z" }, + { url = "https://files.pythonhosted.org/packages/ef/92/466b0d9afd44b8af623139a3599d651c7564fa4152f25f117e1ee5949ffb/greenlet-3.4.0-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c4cd56a9eb7a6444edbc19062f7b6fbc8f287c663b946e3171d899693b1c19fa", size = 665872, upload-time = "2026-04-08T16:40:43.912Z" }, + { url = "https://files.pythonhosted.org/packages/19/da/991cf7cd33662e2df92a1274b7eb4d61769294d38a1bba8a45f31364845e/greenlet-3.4.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e60d38719cb80b3ab5e85f9f1aed4960acfde09868af6762ccb27b260d68f4ed", size = 661861, upload-time = "2026-04-08T15:56:37.269Z" }, + { url = "https://files.pythonhosted.org/packages/0d/14/3395a7ef3e260de0325152ddfe19dffb3e49fe10873b94654352b53ad48e/greenlet-3.4.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:1f85f204c4d54134ae850d401fa435c89cd667d5ce9dc567571776b45941af72", size = 489237, upload-time = "2026-04-08T16:43:09.993Z" }, + { url = "https://files.pythonhosted.org/packages/36/c5/6c2c708e14db3d9caea4b459d8464f58c32047451142fe2cfd90e7458f41/greenlet-3.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7f50c804733b43eded05ae694691c9aa68bca7d0a867d67d4a3f514742a2d53f", size = 1622182, upload-time = "2026-04-08T16:26:24.777Z" }, + { url = "https://files.pythonhosted.org/packages/7a/4c/50c5fed19378e11a29fabab1f6be39ea95358f4a0a07e115a51ca93385d8/greenlet-3.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2d4f0635dc4aa638cda4b2f5a07ae9a2cff9280327b581a3fcb6f317b4fbc38a", size = 1685050, upload-time = "2026-04-08T15:57:36.453Z" }, + { url = "https://files.pythonhosted.org/packages/db/72/85ae954d734703ab48e622c59d4ce35d77ce840c265814af9c078cacc7aa/greenlet-3.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:1a4a48f24681300c640f143ba7c404270e1ebbbcf34331d7104a4ff40f8ea705", size = 245554, upload-time = "2026-04-08T17:03:50.044Z" }, +] + +[[package]] +name = "grpcio" +version = "1.80.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a3/51/1664f6b78fc6ebbd98019a1fd730e83fa78f2db7058f72b1463d3612b8db/greenlet-3.3.2.tar.gz", hash = "sha256:2eaf067fc6d886931c7962e8c6bede15d2f01965560f3359b27c80bde2d151f2", size = 188267, upload-time = "2026-02-20T20:54:15.531Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/ab/1608e5a7578e62113506740b88066bf09888322a311cff602105e619bd87/greenlet-3.3.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:ac8d61d4343b799d1e526db579833d72f23759c71e07181c2d2944e429eb09cd", size = 280358, upload-time = "2026-02-20T20:17:43.971Z" }, - { url = "https://files.pythonhosted.org/packages/a5/23/0eae412a4ade4e6623ff7626e38998cb9b11e9ff1ebacaa021e4e108ec15/greenlet-3.3.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ceec72030dae6ac0c8ed7591b96b70410a8be370b6a477b1dbc072856ad02bd", size = 601217, upload-time = "2026-02-20T20:47:31.462Z" }, - { url = "https://files.pythonhosted.org/packages/f8/16/5b1678a9c07098ecb9ab2dd159fafaf12e963293e61ee8d10ecb55273e5e/greenlet-3.3.2-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2a5be83a45ce6188c045bcc44b0ee037d6a518978de9a5d97438548b953a1ac", size = 611792, upload-time = "2026-02-20T20:55:58.423Z" }, - { url = "https://files.pythonhosted.org/packages/5c/c5/cc09412a29e43406eba18d61c70baa936e299bc27e074e2be3806ed29098/greenlet-3.3.2-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ae9e21c84035c490506c17002f5c8ab25f980205c3e61ddb3a2a2a2e6c411fcb", size = 626250, upload-time = "2026-02-20T21:02:46.596Z" }, - { url = "https://files.pythonhosted.org/packages/50/1f/5155f55bd71cabd03765a4aac9ac446be129895271f73872c36ebd4b04b6/greenlet-3.3.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43e99d1749147ac21dde49b99c9abffcbc1e2d55c67501465ef0930d6e78e070", size = 613875, upload-time = "2026-02-20T20:21:01.102Z" }, - { url = "https://files.pythonhosted.org/packages/fc/dd/845f249c3fcd69e32df80cdab059b4be8b766ef5830a3d0aa9d6cad55beb/greenlet-3.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c956a19350e2c37f2c48b336a3afb4bff120b36076d9d7fb68cb44e05d95b79", size = 1571467, upload-time = "2026-02-20T20:49:33.495Z" }, - { url = "https://files.pythonhosted.org/packages/2a/50/2649fe21fcc2b56659a452868e695634722a6655ba245d9f77f5656010bf/greenlet-3.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6c6f8ba97d17a1e7d664151284cb3315fc5f8353e75221ed4324f84eb162b395", size = 1640001, upload-time = "2026-02-20T20:21:09.154Z" }, - { url = "https://files.pythonhosted.org/packages/9b/40/cc802e067d02af8b60b6771cea7d57e21ef5e6659912814babb42b864713/greenlet-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:34308836d8370bddadb41f5a7ce96879b72e2fdfb4e87729330c6ab52376409f", size = 231081, upload-time = "2026-02-20T20:17:28.121Z" }, - { url = "https://files.pythonhosted.org/packages/58/2e/fe7f36ff1982d6b10a60d5e0740c759259a7d6d2e1dc41da6d96de32fff6/greenlet-3.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:d3a62fa76a32b462a97198e4c9e99afb9ab375115e74e9a83ce180e7a496f643", size = 230331, upload-time = "2026-02-20T20:17:23.34Z" }, - { url = "https://files.pythonhosted.org/packages/ac/48/f8b875fa7dea7dd9b33245e37f065af59df6a25af2f9561efa8d822fde51/greenlet-3.3.2-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:aa6ac98bdfd716a749b84d4034486863fd81c3abde9aa3cf8eff9127981a4ae4", size = 279120, upload-time = "2026-02-20T20:19:01.9Z" }, - { url = "https://files.pythonhosted.org/packages/49/8d/9771d03e7a8b1ee456511961e1b97a6d77ae1dea4a34a5b98eee706689d3/greenlet-3.3.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab0c7e7901a00bc0a7284907273dc165b32e0d109a6713babd04471327ff7986", size = 603238, upload-time = "2026-02-20T20:47:32.873Z" }, - { url = "https://files.pythonhosted.org/packages/59/0e/4223c2bbb63cd5c97f28ffb2a8aee71bdfb30b323c35d409450f51b91e3e/greenlet-3.3.2-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d248d8c23c67d2291ffd47af766e2a3aa9fa1c6703155c099feb11f526c63a92", size = 614219, upload-time = "2026-02-20T20:55:59.817Z" }, - { url = "https://files.pythonhosted.org/packages/94/2b/4d012a69759ac9d77210b8bfb128bc621125f5b20fc398bce3940d036b1c/greenlet-3.3.2-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ccd21bb86944ca9be6d967cf7691e658e43417782bce90b5d2faeda0ff78a7dd", size = 628268, upload-time = "2026-02-20T21:02:48.024Z" }, - { url = "https://files.pythonhosted.org/packages/7a/34/259b28ea7a2a0c904b11cd36c79b8cef8019b26ee5dbe24e73b469dea347/greenlet-3.3.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6997d360a4e6a4e936c0f9625b1c20416b8a0ea18a8e19cabbefc712e7397ab", size = 616774, upload-time = "2026-02-20T20:21:02.454Z" }, - { url = "https://files.pythonhosted.org/packages/0a/03/996c2d1689d486a6e199cb0f1cf9e4aa940c500e01bdf201299d7d61fa69/greenlet-3.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:64970c33a50551c7c50491671265d8954046cb6e8e2999aacdd60e439b70418a", size = 1571277, upload-time = "2026-02-20T20:49:34.795Z" }, - { url = "https://files.pythonhosted.org/packages/d9/c4/2570fc07f34a39f2caf0bf9f24b0a1a0a47bc2e8e465b2c2424821389dfc/greenlet-3.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1a9172f5bf6bd88e6ba5a84e0a68afeac9dc7b6b412b245dd64f52d83c81e55b", size = 1640455, upload-time = "2026-02-20T20:21:10.261Z" }, - { url = "https://files.pythonhosted.org/packages/91/39/5ef5aa23bc545aa0d31e1b9b55822b32c8da93ba657295840b6b34124009/greenlet-3.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:a7945dd0eab63ded0a48e4dcade82939783c172290a7903ebde9e184333ca124", size = 230961, upload-time = "2026-02-20T20:16:58.461Z" }, - { url = "https://files.pythonhosted.org/packages/62/6b/a89f8456dcb06becff288f563618e9f20deed8dd29beea14f9a168aef64b/greenlet-3.3.2-cp313-cp313-win_arm64.whl", hash = "sha256:394ead29063ee3515b4e775216cb756b2e3b4a7e55ae8fd884f17fa579e6b327", size = 230221, upload-time = "2026-02-20T20:17:37.152Z" }, - { url = "https://files.pythonhosted.org/packages/3f/ae/8bffcbd373b57a5992cd077cbe8858fff39110480a9d50697091faea6f39/greenlet-3.3.2-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:8d1658d7291f9859beed69a776c10822a0a799bc4bfe1bd4272bb60e62507dab", size = 279650, upload-time = "2026-02-20T20:18:00.783Z" }, - { url = "https://files.pythonhosted.org/packages/d1/c0/45f93f348fa49abf32ac8439938726c480bd96b2a3c6f4d949ec0124b69f/greenlet-3.3.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18cb1b7337bca281915b3c5d5ae19f4e76d35e1df80f4ad3c1a7be91fadf1082", size = 650295, upload-time = "2026-02-20T20:47:34.036Z" }, - { url = "https://files.pythonhosted.org/packages/b3/de/dd7589b3f2b8372069ab3e4763ea5329940fc7ad9dcd3e272a37516d7c9b/greenlet-3.3.2-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2e47408e8ce1c6f1ceea0dffcdf6ebb85cc09e55c7af407c99f1112016e45e9", size = 662163, upload-time = "2026-02-20T20:56:01.295Z" }, - { url = "https://files.pythonhosted.org/packages/cd/ac/85804f74f1ccea31ba518dcc8ee6f14c79f73fe36fa1beba38930806df09/greenlet-3.3.2-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e3cb43ce200f59483eb82949bf1835a99cf43d7571e900d7c8d5c62cdf25d2f9", size = 675371, upload-time = "2026-02-20T21:02:49.664Z" }, - { url = "https://files.pythonhosted.org/packages/d2/d8/09bfa816572a4d83bccd6750df1926f79158b1c36c5f73786e26dbe4ee38/greenlet-3.3.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63d10328839d1973e5ba35e98cccbca71b232b14051fd957b6f8b6e8e80d0506", size = 664160, upload-time = "2026-02-20T20:21:04.015Z" }, - { url = "https://files.pythonhosted.org/packages/48/cf/56832f0c8255d27f6c35d41b5ec91168d74ec721d85f01a12131eec6b93c/greenlet-3.3.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e4ab3cfb02993c8cc248ea73d7dae6cec0253e9afa311c9b37e603ca9fad2ce", size = 1619181, upload-time = "2026-02-20T20:49:36.052Z" }, - { url = "https://files.pythonhosted.org/packages/0a/23/b90b60a4aabb4cec0796e55f25ffbfb579a907c3898cd2905c8918acaa16/greenlet-3.3.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94ad81f0fd3c0c0681a018a976e5c2bd2ca2d9d94895f23e7bb1af4e8af4e2d5", size = 1687713, upload-time = "2026-02-20T20:21:11.684Z" }, - { url = "https://files.pythonhosted.org/packages/f3/ca/2101ca3d9223a1dc125140dbc063644dca76df6ff356531eb27bc267b446/greenlet-3.3.2-cp314-cp314-win_amd64.whl", hash = "sha256:8c4dd0f3997cf2512f7601563cc90dfb8957c0cff1e3a1b23991d4ea1776c492", size = 232034, upload-time = "2026-02-20T20:20:08.186Z" }, - { url = "https://files.pythonhosted.org/packages/f6/4a/ecf894e962a59dea60f04877eea0fd5724618da89f1867b28ee8b91e811f/greenlet-3.3.2-cp314-cp314-win_arm64.whl", hash = "sha256:cd6f9e2bbd46321ba3bbb4c8a15794d32960e3b0ae2cc4d49a1a53d314805d71", size = 231437, upload-time = "2026-02-20T20:18:59.722Z" }, - { url = "https://files.pythonhosted.org/packages/98/6d/8f2ef704e614bcf58ed43cfb8d87afa1c285e98194ab2cfad351bf04f81e/greenlet-3.3.2-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:e26e72bec7ab387ac80caa7496e0f908ff954f31065b0ffc1f8ecb1338b11b54", size = 286617, upload-time = "2026-02-20T20:19:29.856Z" }, - { url = "https://files.pythonhosted.org/packages/5e/0d/93894161d307c6ea237a43988f27eba0947b360b99ac5239ad3fe09f0b47/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b466dff7a4ffda6ca975979bab80bdadde979e29fc947ac3be4451428d8b0e4", size = 655189, upload-time = "2026-02-20T20:47:35.742Z" }, - { url = "https://files.pythonhosted.org/packages/f5/2c/d2d506ebd8abcb57386ec4f7ba20f4030cbe56eae541bc6fd6ef399c0b41/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b8bddc5b73c9720bea487b3bffdb1840fe4e3656fba3bd40aa1489e9f37877ff", size = 658225, upload-time = "2026-02-20T20:56:02.527Z" }, - { url = "https://files.pythonhosted.org/packages/d1/67/8197b7e7e602150938049d8e7f30de1660cfb87e4c8ee349b42b67bdb2e1/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:59b3e2c40f6706b05a9cd299c836c6aa2378cabe25d021acd80f13abf81181cf", size = 666581, upload-time = "2026-02-20T21:02:51.526Z" }, - { url = "https://files.pythonhosted.org/packages/8e/30/3a09155fbf728673a1dea713572d2d31159f824a37c22da82127056c44e4/greenlet-3.3.2-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b26b0f4428b871a751968285a1ac9648944cea09807177ac639b030bddebcea4", size = 657907, upload-time = "2026-02-20T20:21:05.259Z" }, - { url = "https://files.pythonhosted.org/packages/f3/fd/d05a4b7acd0154ed758797f0a43b4c0962a843bedfe980115e842c5b2d08/greenlet-3.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1fb39a11ee2e4d94be9a76671482be9398560955c9e568550de0224e41104727", size = 1618857, upload-time = "2026-02-20T20:49:37.309Z" }, - { url = "https://files.pythonhosted.org/packages/6f/e1/50ee92a5db521de8f35075b5eff060dd43d39ebd46c2181a2042f7070385/greenlet-3.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:20154044d9085151bc309e7689d6f7ba10027f8f5a8c0676ad398b951913d89e", size = 1680010, upload-time = "2026-02-20T20:21:13.427Z" }, - { url = "https://files.pythonhosted.org/packages/29/4b/45d90626aef8e65336bed690106d1382f7a43665e2249017e9527df8823b/greenlet-3.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c04c5e06ec3e022cbfe2cd4a846e1d4e50087444f875ff6d2c2ad8445495cf1a", size = 237086, upload-time = "2026-02-20T20:20:45.786Z" }, +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b7/48/af6173dbca4454f4637a4678b67f52ca7e0c1ed7d5894d89d434fecede05/grpcio-1.80.0.tar.gz", hash = "sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257", size = 12978905, upload-time = "2026-03-30T08:49:10.502Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/e8/a2b749265eb3415abc94f2e619bbd9e9707bebdda787e61c593004ec927a/grpcio-1.80.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:c624cc9f1008361014378c9d776de7182b11fe8b2e5a81bc69f23a295f2a1ad0", size = 6015616, upload-time = "2026-03-30T08:47:13.428Z" }, + { url = "https://files.pythonhosted.org/packages/3e/97/b1282161a15d699d1e90c360df18d19165a045ce1c343c7f313f5e8a0b77/grpcio-1.80.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:f49eddcac43c3bf350c0385366a58f36bed8cc2c0ec35ef7b74b49e56552c0c2", size = 12014204, upload-time = "2026-03-30T08:47:15.873Z" }, + { url = "https://files.pythonhosted.org/packages/6e/5e/d319c6e997b50c155ac5a8cb12f5173d5b42677510e886d250d50264949d/grpcio-1.80.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d334591df610ab94714048e0d5b4f3dd5ad1bee74dfec11eee344220077a79de", size = 6563866, upload-time = "2026-03-30T08:47:18.588Z" }, + { url = "https://files.pythonhosted.org/packages/ae/f6/fdd975a2cb4d78eb67769a7b3b3830970bfa2e919f1decf724ae4445f42c/grpcio-1.80.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:0cb517eb1d0d0aaf1d87af7cc5b801d686557c1d88b2619f5e31fab3c2315921", size = 7273060, upload-time = "2026-03-30T08:47:21.113Z" }, + { url = "https://files.pythonhosted.org/packages/db/f0/a3deb5feba60d9538a962913e37bd2e69a195f1c3376a3dd44fe0427e996/grpcio-1.80.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4e78c4ac0d97dc2e569b2f4bcbbb447491167cb358d1a389fc4af71ab6f70411", size = 6782121, upload-time = "2026-03-30T08:47:23.827Z" }, + { url = "https://files.pythonhosted.org/packages/ca/84/36c6dcfddc093e108141f757c407902a05085e0c328007cb090d56646cdf/grpcio-1.80.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2ed770b4c06984f3b47eb0517b1c69ad0b84ef3f40128f51448433be904634cd", size = 7383811, upload-time = "2026-03-30T08:47:26.517Z" }, + { url = "https://files.pythonhosted.org/packages/7c/ef/f3a77e3dc5b471a0ec86c564c98d6adfa3510d38f8ee99010410858d591e/grpcio-1.80.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:256507e2f524092f1473071a05e65a5b10d84b82e3ff24c5b571513cfaa61e2f", size = 8393860, upload-time = "2026-03-30T08:47:29.439Z" }, + { url = "https://files.pythonhosted.org/packages/9b/8d/9d4d27ed7f33d109c50d6b5ce578a9914aa68edab75d65869a17e630a8d1/grpcio-1.80.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a6284a5d907c37db53350645567c522be314bac859a64a7a5ca63b77bb7958f", size = 7830132, upload-time = "2026-03-30T08:47:33.254Z" }, + { url = "https://files.pythonhosted.org/packages/14/e4/9990b41c6d7a44e1e9dee8ac11d7a9802ba1378b40d77468a7761d1ad288/grpcio-1.80.0-cp312-cp312-win32.whl", hash = "sha256:c71309cfce2f22be26aa4a847357c502db6c621f1a49825ae98aa0907595b193", size = 4140904, upload-time = "2026-03-30T08:47:35.319Z" }, + { url = "https://files.pythonhosted.org/packages/2f/2c/296f6138caca1f4b92a31ace4ae1b87dab692fc16a7a3417af3bb3c805bf/grpcio-1.80.0-cp312-cp312-win_amd64.whl", hash = "sha256:9fe648599c0e37594c4809d81a9e77bd138cc82eb8baa71b6a86af65426723ff", size = 4880944, upload-time = "2026-03-30T08:47:37.831Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/7c3c25789e3f069e581dc342e03613c5b1cb012c4e8c7d9d5cf960a75856/grpcio-1.80.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:e9e408fc016dffd20661f0126c53d8a31c2821b5c13c5d67a0f5ed5de93319ad", size = 6017243, upload-time = "2026-03-30T08:47:40.075Z" }, + { url = "https://files.pythonhosted.org/packages/04/19/21a9806eb8240e174fd1ab0cd5b9aa948bb0e05c2f2f55f9d5d7405e6d08/grpcio-1.80.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:92d787312e613754d4d8b9ca6d3297e69994a7912a32fa38c4c4e01c272974b0", size = 12010840, upload-time = "2026-03-30T08:47:43.11Z" }, + { url = "https://files.pythonhosted.org/packages/18/3a/23347d35f76f639e807fb7a36fad3068aed100996849a33809591f26eca6/grpcio-1.80.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ac393b58aa16991a2f1144ec578084d544038c12242da3a215966b512904d0f", size = 6567644, upload-time = "2026-03-30T08:47:46.806Z" }, + { url = "https://files.pythonhosted.org/packages/ff/40/96e07ecb604a6a67ae6ab151e3e35b132875d98bc68ec65f3e5ab3e781d7/grpcio-1.80.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:68e5851ac4b9afe07e7f84483803ad167852570d65326b34d54ca560bfa53fb6", size = 7277830, upload-time = "2026-03-30T08:47:49.643Z" }, + { url = "https://files.pythonhosted.org/packages/9b/e2/da1506ecea1f34a5e365964644b35edef53803052b763ca214ba3870c856/grpcio-1.80.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:873ff5d17d68992ef6605330127425d2fc4e77e612fa3c3e0ed4e668685e3140", size = 6783216, upload-time = "2026-03-30T08:47:52.817Z" }, + { url = "https://files.pythonhosted.org/packages/44/83/3b20ff58d0c3b7f6caaa3af9a4174d4023701df40a3f39f7f1c8e7c48f9d/grpcio-1.80.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2bea16af2750fd0a899bf1abd9022244418b55d1f37da2202249ba4ba673838d", size = 7385866, upload-time = "2026-03-30T08:47:55.687Z" }, + { url = "https://files.pythonhosted.org/packages/47/45/55c507599c5520416de5eefecc927d6a0d7af55e91cfffb2e410607e5744/grpcio-1.80.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba0db34f7e1d803a878284cd70e4c63cb6ae2510ba51937bf8f45ba997cefcf7", size = 8391602, upload-time = "2026-03-30T08:47:58.303Z" }, + { url = "https://files.pythonhosted.org/packages/10/bb/dd06f4c24c01db9cf11341b547d0a016b2c90ed7dbbb086a5710df7dd1d7/grpcio-1.80.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8eb613f02d34721f1acf3626dfdb3545bd3c8505b0e52bf8b5710a28d02e8aa7", size = 7826752, upload-time = "2026-03-30T08:48:01.311Z" }, + { url = "https://files.pythonhosted.org/packages/f9/1e/9d67992ba23371fd63d4527096eb8c6b76d74d52b500df992a3343fd7251/grpcio-1.80.0-cp313-cp313-win32.whl", hash = "sha256:93b6f823810720912fd131f561f91f5fed0fda372b6b7028a2681b8194d5d294", size = 4142310, upload-time = "2026-03-30T08:48:04.594Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e6/283326a27da9e2c3038bc93eeea36fb118ce0b2d03922a9cda6688f53c5b/grpcio-1.80.0-cp313-cp313-win_amd64.whl", hash = "sha256:e172cf795a3ba5246d3529e4d34c53db70e888fa582a8ffebd2e6e48bc0cba50", size = 4882833, upload-time = "2026-03-30T08:48:07.363Z" }, + { url = "https://files.pythonhosted.org/packages/c5/6d/e65307ce20f5a09244ba9e9d8476e99fb039de7154f37fb85f26978b59c3/grpcio-1.80.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:3d4147a97c8344d065d01bbf8b6acec2cf86fb0400d40696c8bdad34a64ffc0e", size = 6017376, upload-time = "2026-03-30T08:48:10.005Z" }, + { url = "https://files.pythonhosted.org/packages/69/10/9cef5d9650c72625a699c549940f0abb3c4bfdb5ed45a5ce431f92f31806/grpcio-1.80.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:d8e11f167935b3eb089ac9038e1a063e6d7dbe995c0bb4a661e614583352e76f", size = 12018133, upload-time = "2026-03-30T08:48:12.927Z" }, + { url = "https://files.pythonhosted.org/packages/04/82/983aabaad82ba26113caceeb9091706a0696b25da004fe3defb5b346e15b/grpcio-1.80.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f14b618fc30de822681ee986cfdcc2d9327229dc4c98aed16896761cacd468b9", size = 6574748, upload-time = "2026-03-30T08:48:16.386Z" }, + { url = "https://files.pythonhosted.org/packages/07/d7/031666ef155aa0bf399ed7e19439656c38bbd143779ae0861b038ce82abd/grpcio-1.80.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4ed39fbdcf9b87370f6e8df4e39ca7b38b3e5e9d1b0013c7b6be9639d6578d14", size = 7277711, upload-time = "2026-03-30T08:48:19.627Z" }, + { url = "https://files.pythonhosted.org/packages/e8/43/f437a78f7f4f1d311804189e8f11fb311a01049b2e08557c1068d470cb2e/grpcio-1.80.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2dcc70e9f0ba987526e8e8603a610fb4f460e42899e74e7a518bf3c68fe1bf05", size = 6785372, upload-time = "2026-03-30T08:48:22.373Z" }, + { url = "https://files.pythonhosted.org/packages/93/3d/f6558e9c6296cb4227faa5c43c54a34c68d32654b829f53288313d16a86e/grpcio-1.80.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:448c884b668b868562b1bda833c5fce6272d26e1926ec46747cda05741d302c1", size = 7395268, upload-time = "2026-03-30T08:48:25.638Z" }, + { url = "https://files.pythonhosted.org/packages/06/21/0fdd77e84720b08843c371a2efa6f2e19dbebf56adc72df73d891f5506f0/grpcio-1.80.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a1dc80fe55685b4a543555e6eef975303b36c8db1023b1599b094b92aa77965f", size = 8392000, upload-time = "2026-03-30T08:48:28.974Z" }, + { url = "https://files.pythonhosted.org/packages/f5/68/67f4947ed55d2e69f2cc199ab9fd85e0a0034d813bbeef84df6d2ba4d4b7/grpcio-1.80.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:31b9ac4ad1aa28ffee5503821fafd09e4da0a261ce1c1281c6c8da0423c83b6e", size = 7828477, upload-time = "2026-03-30T08:48:32.054Z" }, + { url = "https://files.pythonhosted.org/packages/44/b6/8d4096691b2e385e8271911a0de4f35f0a6c7d05aff7098e296c3de86939/grpcio-1.80.0-cp314-cp314-win32.whl", hash = "sha256:367ce30ba67d05e0592470428f0ec1c31714cab9ef19b8f2e37be1f4c7d32fae", size = 4218563, upload-time = "2026-03-30T08:48:34.538Z" }, + { url = "https://files.pythonhosted.org/packages/e5/8c/bbe6baf2557262834f2070cf668515fa308b2d38a4bbf771f8f7872a7036/grpcio-1.80.0-cp314-cp314-win_amd64.whl", hash = "sha256:3b01e1f5464c583d2f567b2e46ff0d516ef979978f72091fd81f5ab7fa6e2e7f", size = 5019457, upload-time = "2026-03-30T08:48:37.308Z" }, ] [[package]] -name = "idna" -version = "3.11" +name = "grpcio-status" +version = "1.80.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +dependencies = [ + { name = "googleapis-common-protos" }, + { name = "grpcio" }, + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/ed/105f619bdd00cb47a49aa2feea6232ea2bbb04199d52a22cc6a7d603b5cb/grpcio_status-1.80.0.tar.gz", hash = "sha256:df73802a4c89a3ea88aa2aff971e886fccce162bc2e6511408b3d67a144381cd", size = 13901, upload-time = "2026-03-30T08:54:34.784Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/76/80/58cd2dfc19a07d022abe44bde7c365627f6c7cb6f692ada6c65ca437d09a/grpcio_status-1.80.0-py3-none-any.whl", hash = "sha256:4b56990363af50dbf2c2ebb80f1967185c07d87aa25aa2bea45ddb75fc181dbe", size = 14638, upload-time = "2026-03-30T08:54:01.569Z" }, ] [[package]] -name = "ifaddr" -version = "0.2.0" +name = "idna" +version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/ac/fb4c578f4a3256561548cd825646680edcadb9440f3f68add95ade1eb791/ifaddr-0.2.0.tar.gz", hash = "sha256:cc0cbfcaabf765d44595825fb96a99bb12c79716b73b44330ea38ee2b0c4aed4", size = 10485, upload-time = "2022-06-15T21:40:27.561Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/1f/19ebc343cc71a7ffa78f17018535adc5cbdd87afb31d7c34874680148b32/ifaddr-0.2.0-py3-none-any.whl", hash = "sha256:085e0305cfe6f16ab12d72e2024030f5d52674afad6911bb1eee207177b8a748", size = 12314, upload-time = "2022-06-15T21:40:25.756Z" }, + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] [[package]] @@ -875,62 +1155,62 @@ wheels = [ [[package]] name = "librt" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/56/9c/b4b0c54d84da4a94b37bd44151e46d5e583c9534c7e02250b961b1b6d8a8/librt-0.8.1.tar.gz", hash = "sha256:be46a14693955b3bd96014ccbdb8339ee8c9346fbe11c1b78901b55125f14c73", size = 177471, upload-time = "2026-02-17T16:13:06.101Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/21/d39b0a87ac52fc98f621fb6f8060efb017a767ebbbac2f99fbcbc9ddc0d7/librt-0.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a28f2612ab566b17f3698b0da021ff9960610301607c9a5e8eaca62f5e1c350a", size = 66516, upload-time = "2026-02-17T16:11:41.604Z" }, - { url = "https://files.pythonhosted.org/packages/69/f1/46375e71441c43e8ae335905e069f1c54febee63a146278bcee8782c84fd/librt-0.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:60a78b694c9aee2a0f1aaeaa7d101cf713e92e8423a941d2897f4fa37908dab9", size = 68634, upload-time = "2026-02-17T16:11:43.268Z" }, - { url = "https://files.pythonhosted.org/packages/0a/33/c510de7f93bf1fa19e13423a606d8189a02624a800710f6e6a0a0f0784b3/librt-0.8.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:758509ea3f1eba2a57558e7e98f4659d0ea7670bff49673b0dde18a3c7e6c0eb", size = 198941, upload-time = "2026-02-17T16:11:44.28Z" }, - { url = "https://files.pythonhosted.org/packages/dd/36/e725903416409a533d92398e88ce665476f275081d0d7d42f9c4951999e5/librt-0.8.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:039b9f2c506bd0ab0f8725aa5ba339c6f0cd19d3b514b50d134789809c24285d", size = 209991, upload-time = "2026-02-17T16:11:45.462Z" }, - { url = "https://files.pythonhosted.org/packages/30/7a/8d908a152e1875c9f8eac96c97a480df425e657cdb47854b9efaa4998889/librt-0.8.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5bb54f1205a3a6ab41a6fd71dfcdcbd278670d3a90ca502a30d9da583105b6f7", size = 224476, upload-time = "2026-02-17T16:11:46.542Z" }, - { url = "https://files.pythonhosted.org/packages/a8/b8/a22c34f2c485b8903a06f3fe3315341fe6876ef3599792344669db98fcff/librt-0.8.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:05bd41cdee35b0c59c259f870f6da532a2c5ca57db95b5f23689fcb5c9e42440", size = 217518, upload-time = "2026-02-17T16:11:47.746Z" }, - { url = "https://files.pythonhosted.org/packages/79/6f/5c6fea00357e4f82ba44f81dbfb027921f1ab10e320d4a64e1c408d035d9/librt-0.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adfab487facf03f0d0857b8710cf82d0704a309d8ffc33b03d9302b4c64e91a9", size = 225116, upload-time = "2026-02-17T16:11:49.298Z" }, - { url = "https://files.pythonhosted.org/packages/f2/a0/95ced4e7b1267fe1e2720a111685bcddf0e781f7e9e0ce59d751c44dcfe5/librt-0.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:153188fe98a72f206042be10a2c6026139852805215ed9539186312d50a8e972", size = 217751, upload-time = "2026-02-17T16:11:50.49Z" }, - { url = "https://files.pythonhosted.org/packages/93/c2/0517281cb4d4101c27ab59472924e67f55e375bc46bedae94ac6dc6e1902/librt-0.8.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:dd3c41254ee98604b08bd5b3af5bf0a89740d4ee0711de95b65166bf44091921", size = 218378, upload-time = "2026-02-17T16:11:51.783Z" }, - { url = "https://files.pythonhosted.org/packages/43/e8/37b3ac108e8976888e559a7b227d0ceac03c384cfd3e7a1c2ee248dbae79/librt-0.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e0d138c7ae532908cbb342162b2611dbd4d90c941cd25ab82084aaf71d2c0bd0", size = 241199, upload-time = "2026-02-17T16:11:53.561Z" }, - { url = "https://files.pythonhosted.org/packages/4b/5b/35812d041c53967fedf551a39399271bbe4257e681236a2cf1a69c8e7fa1/librt-0.8.1-cp312-cp312-win32.whl", hash = "sha256:43353b943613c5d9c49a25aaffdba46f888ec354e71e3529a00cca3f04d66a7a", size = 54917, upload-time = "2026-02-17T16:11:54.758Z" }, - { url = "https://files.pythonhosted.org/packages/de/d1/fa5d5331b862b9775aaf2a100f5ef86854e5d4407f71bddf102f4421e034/librt-0.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:ff8baf1f8d3f4b6b7257fcb75a501f2a5499d0dda57645baa09d4d0d34b19444", size = 62017, upload-time = "2026-02-17T16:11:55.748Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7c/c614252f9acda59b01a66e2ddfd243ed1c7e1deab0293332dfbccf862808/librt-0.8.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f2ae3725904f7377e11cc37722d5d401e8b3d5851fb9273d7f4fe04f6b3d37d", size = 52441, upload-time = "2026-02-17T16:11:56.801Z" }, - { url = "https://files.pythonhosted.org/packages/c5/3c/f614c8e4eaac7cbf2bbdf9528790b21d89e277ee20d57dc6e559c626105f/librt-0.8.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e6bad1cd94f6764e1e21950542f818a09316645337fd5ab9a7acc45d99a8f35", size = 66529, upload-time = "2026-02-17T16:11:57.809Z" }, - { url = "https://files.pythonhosted.org/packages/ab/96/5836544a45100ae411eda07d29e3d99448e5258b6e9c8059deb92945f5c2/librt-0.8.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cf450f498c30af55551ba4f66b9123b7185362ec8b625a773b3d39aa1a717583", size = 68669, upload-time = "2026-02-17T16:11:58.843Z" }, - { url = "https://files.pythonhosted.org/packages/06/53/f0b992b57af6d5531bf4677d75c44f095f2366a1741fb695ee462ae04b05/librt-0.8.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:eca45e982fa074090057132e30585a7e8674e9e885d402eae85633e9f449ce6c", size = 199279, upload-time = "2026-02-17T16:11:59.862Z" }, - { url = "https://files.pythonhosted.org/packages/f3/ad/4848cc16e268d14280d8168aee4f31cea92bbd2b79ce33d3e166f2b4e4fc/librt-0.8.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c3811485fccfda840861905b8c70bba5ec094e02825598bb9d4ca3936857a04", size = 210288, upload-time = "2026-02-17T16:12:00.954Z" }, - { url = "https://files.pythonhosted.org/packages/52/05/27fdc2e95de26273d83b96742d8d3b7345f2ea2bdbd2405cc504644f2096/librt-0.8.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e4af413908f77294605e28cfd98063f54b2c790561383971d2f52d113d9c363", size = 224809, upload-time = "2026-02-17T16:12:02.108Z" }, - { url = "https://files.pythonhosted.org/packages/7a/d0/78200a45ba3240cb042bc597d6f2accba9193a2c57d0356268cbbe2d0925/librt-0.8.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5212a5bd7fae98dae95710032902edcd2ec4dc994e883294f75c857b83f9aba0", size = 218075, upload-time = "2026-02-17T16:12:03.631Z" }, - { url = "https://files.pythonhosted.org/packages/af/72/a210839fa74c90474897124c064ffca07f8d4b347b6574d309686aae7ca6/librt-0.8.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e692aa2d1d604e6ca12d35e51fdc36f4cda6345e28e36374579f7ef3611b3012", size = 225486, upload-time = "2026-02-17T16:12:04.725Z" }, - { url = "https://files.pythonhosted.org/packages/a3/c1/a03cc63722339ddbf087485f253493e2b013039f5b707e8e6016141130fa/librt-0.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4be2a5c926b9770c9e08e717f05737a269b9d0ebc5d2f0060f0fe3fe9ce47acb", size = 218219, upload-time = "2026-02-17T16:12:05.828Z" }, - { url = "https://files.pythonhosted.org/packages/58/f5/fff6108af0acf941c6f274a946aea0e484bd10cd2dc37610287ce49388c5/librt-0.8.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fd1a720332ea335ceb544cf0a03f81df92abd4bb887679fd1e460976b0e6214b", size = 218750, upload-time = "2026-02-17T16:12:07.09Z" }, - { url = "https://files.pythonhosted.org/packages/71/67/5a387bfef30ec1e4b4f30562c8586566faf87e47d696768c19feb49e3646/librt-0.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:93c2af9e01e0ef80d95ae3c720be101227edae5f2fe7e3dc63d8857fadfc5a1d", size = 241624, upload-time = "2026-02-17T16:12:08.43Z" }, - { url = "https://files.pythonhosted.org/packages/d4/be/24f8502db11d405232ac1162eb98069ca49c3306c1d75c6ccc61d9af8789/librt-0.8.1-cp313-cp313-win32.whl", hash = "sha256:086a32dbb71336627e78cc1d6ee305a68d038ef7d4c39aaff41ae8c9aa46e91a", size = 54969, upload-time = "2026-02-17T16:12:09.633Z" }, - { url = "https://files.pythonhosted.org/packages/5c/73/c9fdf6cb2a529c1a092ce769a12d88c8cca991194dfe641b6af12fa964d2/librt-0.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:e11769a1dbda4da7b00a76cfffa67aa47cfa66921d2724539eee4b9ede780b79", size = 62000, upload-time = "2026-02-17T16:12:10.632Z" }, - { url = "https://files.pythonhosted.org/packages/d3/97/68f80ca3ac4924f250cdfa6e20142a803e5e50fca96ef5148c52ee8c10ea/librt-0.8.1-cp313-cp313-win_arm64.whl", hash = "sha256:924817ab3141aca17893386ee13261f1d100d1ef410d70afe4389f2359fea4f0", size = 52495, upload-time = "2026-02-17T16:12:11.633Z" }, - { url = "https://files.pythonhosted.org/packages/c9/6a/907ef6800f7bca71b525a05f1839b21f708c09043b1c6aa77b6b827b3996/librt-0.8.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6cfa7fe54fd4d1f47130017351a959fe5804bda7a0bc7e07a2cdbc3fdd28d34f", size = 66081, upload-time = "2026-02-17T16:12:12.766Z" }, - { url = "https://files.pythonhosted.org/packages/1b/18/25e991cd5640c9fb0f8d91b18797b29066b792f17bf8493da183bf5caabe/librt-0.8.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:228c2409c079f8c11fb2e5d7b277077f694cb93443eb760e00b3b83cb8b3176c", size = 68309, upload-time = "2026-02-17T16:12:13.756Z" }, - { url = "https://files.pythonhosted.org/packages/a4/36/46820d03f058cfb5a9de5940640ba03165ed8aded69e0733c417bb04df34/librt-0.8.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7aae78ab5e3206181780e56912d1b9bb9f90a7249ce12f0e8bf531d0462dd0fc", size = 196804, upload-time = "2026-02-17T16:12:14.818Z" }, - { url = "https://files.pythonhosted.org/packages/59/18/5dd0d3b87b8ff9c061849fbdb347758d1f724b9a82241aa908e0ec54ccd0/librt-0.8.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:172d57ec04346b047ca6af181e1ea4858086c80bdf455f61994c4aa6fc3f866c", size = 206907, upload-time = "2026-02-17T16:12:16.513Z" }, - { url = "https://files.pythonhosted.org/packages/d1/96/ef04902aad1424fd7299b62d1890e803e6ab4018c3044dca5922319c4b97/librt-0.8.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b1977c4ea97ce5eb7755a78fae68d87e4102e4aaf54985e8b56806849cc06a3", size = 221217, upload-time = "2026-02-17T16:12:17.906Z" }, - { url = "https://files.pythonhosted.org/packages/6d/ff/7e01f2dda84a8f5d280637a2e5827210a8acca9a567a54507ef1c75b342d/librt-0.8.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:10c42e1f6fd06733ef65ae7bebce2872bcafd8d6e6b0a08fe0a05a23b044fb14", size = 214622, upload-time = "2026-02-17T16:12:19.108Z" }, - { url = "https://files.pythonhosted.org/packages/1e/8c/5b093d08a13946034fed57619742f790faf77058558b14ca36a6e331161e/librt-0.8.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4c8dfa264b9193c4ee19113c985c95f876fae5e51f731494fc4e0cf594990ba7", size = 221987, upload-time = "2026-02-17T16:12:20.331Z" }, - { url = "https://files.pythonhosted.org/packages/d3/cc/86b0b3b151d40920ad45a94ce0171dec1aebba8a9d72bb3fa00c73ab25dd/librt-0.8.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:01170b6729a438f0dedc4a26ed342e3dc4f02d1000b4b19f980e1877f0c297e6", size = 215132, upload-time = "2026-02-17T16:12:21.54Z" }, - { url = "https://files.pythonhosted.org/packages/fc/be/8588164a46edf1e69858d952654e216a9a91174688eeefb9efbb38a9c799/librt-0.8.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:7b02679a0d783bdae30d443025b94465d8c3dc512f32f5b5031f93f57ac32071", size = 215195, upload-time = "2026-02-17T16:12:23.073Z" }, - { url = "https://files.pythonhosted.org/packages/f5/f2/0b9279bea735c734d69344ecfe056c1ba211694a72df10f568745c899c76/librt-0.8.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:190b109bb69592a3401fe1ffdea41a2e73370ace2ffdc4a0e8e2b39cdea81b78", size = 237946, upload-time = "2026-02-17T16:12:24.275Z" }, - { url = "https://files.pythonhosted.org/packages/e9/cc/5f2a34fbc8aeb35314a3641f9956fa9051a947424652fad9882be7a97949/librt-0.8.1-cp314-cp314-win32.whl", hash = "sha256:e70a57ecf89a0f64c24e37f38d3fe217a58169d2fe6ed6d70554964042474023", size = 50689, upload-time = "2026-02-17T16:12:25.766Z" }, - { url = "https://files.pythonhosted.org/packages/a0/76/cd4d010ab2147339ca2b93e959c3686e964edc6de66ddacc935c325883d7/librt-0.8.1-cp314-cp314-win_amd64.whl", hash = "sha256:7e2f3edca35664499fbb36e4770650c4bd4a08abc1f4458eab9df4ec56389730", size = 57875, upload-time = "2026-02-17T16:12:27.465Z" }, - { url = "https://files.pythonhosted.org/packages/84/0f/2143cb3c3ca48bd3379dcd11817163ca50781927c4537345d608b5045998/librt-0.8.1-cp314-cp314-win_arm64.whl", hash = "sha256:0d2f82168e55ddefd27c01c654ce52379c0750ddc31ee86b4b266bcf4d65f2a3", size = 48058, upload-time = "2026-02-17T16:12:28.556Z" }, - { url = "https://files.pythonhosted.org/packages/d2/0e/9b23a87e37baf00311c3efe6b48d6b6c168c29902dfc3f04c338372fd7db/librt-0.8.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2c74a2da57a094bd48d03fa5d196da83d2815678385d2978657499063709abe1", size = 68313, upload-time = "2026-02-17T16:12:29.659Z" }, - { url = "https://files.pythonhosted.org/packages/db/9a/859c41e5a4f1c84200a7d2b92f586aa27133c8243b6cac9926f6e54d01b9/librt-0.8.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a355d99c4c0d8e5b770313b8b247411ed40949ca44e33e46a4789b9293a907ee", size = 70994, upload-time = "2026-02-17T16:12:31.516Z" }, - { url = "https://files.pythonhosted.org/packages/4c/28/10605366ee599ed34223ac2bf66404c6fb59399f47108215d16d5ad751a8/librt-0.8.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:2eb345e8b33fb748227409c9f1233d4df354d6e54091f0e8fc53acdb2ffedeb7", size = 220770, upload-time = "2026-02-17T16:12:33.294Z" }, - { url = "https://files.pythonhosted.org/packages/af/8d/16ed8fd452dafae9c48d17a6bc1ee3e818fd40ef718d149a8eff2c9f4ea2/librt-0.8.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9be2f15e53ce4e83cc08adc29b26fb5978db62ef2a366fbdf716c8a6c8901040", size = 235409, upload-time = "2026-02-17T16:12:35.443Z" }, - { url = "https://files.pythonhosted.org/packages/89/1b/7bdf3e49349c134b25db816e4a3db6b94a47ac69d7d46b1e682c2c4949be/librt-0.8.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:785ae29c1f5c6e7c2cde2c7c0e148147f4503da3abc5d44d482068da5322fd9e", size = 246473, upload-time = "2026-02-17T16:12:36.656Z" }, - { url = "https://files.pythonhosted.org/packages/4e/8a/91fab8e4fd2a24930a17188c7af5380eb27b203d72101c9cc000dbdfd95a/librt-0.8.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1d3a7da44baf692f0c6aeb5b2a09c5e6fc7a703bca9ffa337ddd2e2da53f7732", size = 238866, upload-time = "2026-02-17T16:12:37.849Z" }, - { url = "https://files.pythonhosted.org/packages/b9/e0/c45a098843fc7c07e18a7f8a24ca8496aecbf7bdcd54980c6ca1aaa79a8e/librt-0.8.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5fc48998000cbc39ec0d5311312dda93ecf92b39aaf184c5e817d5d440b29624", size = 250248, upload-time = "2026-02-17T16:12:39.445Z" }, - { url = "https://files.pythonhosted.org/packages/82/30/07627de23036640c952cce0c1fe78972e77d7d2f8fd54fa5ef4554ff4a56/librt-0.8.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e96baa6820280077a78244b2e06e416480ed859bbd8e5d641cf5742919d8beb4", size = 240629, upload-time = "2026-02-17T16:12:40.889Z" }, - { url = "https://files.pythonhosted.org/packages/fb/c1/55bfe1ee3542eba055616f9098eaf6eddb966efb0ca0f44eaa4aba327307/librt-0.8.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31362dbfe297b23590530007062c32c6f6176f6099646bb2c95ab1b00a57c382", size = 239615, upload-time = "2026-02-17T16:12:42.446Z" }, - { url = "https://files.pythonhosted.org/packages/2b/39/191d3d28abc26c9099b19852e6c99f7f6d400b82fa5a4e80291bd3803e19/librt-0.8.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc3656283d11540ab0ea01978378e73e10002145117055e03722417aeab30994", size = 263001, upload-time = "2026-02-17T16:12:43.627Z" }, - { url = "https://files.pythonhosted.org/packages/b9/eb/7697f60fbe7042ab4e88f4ee6af496b7f222fffb0a4e3593ef1f29f81652/librt-0.8.1-cp314-cp314t-win32.whl", hash = "sha256:738f08021b3142c2918c03692608baed43bc51144c29e35807682f8070ee2a3a", size = 51328, upload-time = "2026-02-17T16:12:45.148Z" }, - { url = "https://files.pythonhosted.org/packages/7c/72/34bf2eb7a15414a23e5e70ecb9440c1d3179f393d9349338a91e2781c0fb/librt-0.8.1-cp314-cp314t-win_amd64.whl", hash = "sha256:89815a22daf9c51884fb5dbe4f1ef65ee6a146e0b6a8df05f753e2e4a9359bf4", size = 58722, upload-time = "2026-02-17T16:12:46.85Z" }, - { url = "https://files.pythonhosted.org/packages/b2/c8/d148e041732d631fc76036f8b30fae4e77b027a1e95b7a84bb522481a940/librt-0.8.1-cp314-cp314t-win_arm64.whl", hash = "sha256:bf512a71a23504ed08103a13c941f763db13fb11177beb3d9244c98c29fb4a61", size = 48755, upload-time = "2026-02-17T16:12:47.943Z" }, +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/6b/3d5c13fb3e3c4f43206c8f9dfed13778c2ed4f000bacaa0b7ce3c402a265/librt-0.9.0.tar.gz", hash = "sha256:a0951822531e7aee6e0dfb556b30d5ee36bbe234faf60c20a16c01be3530869d", size = 184368, upload-time = "2026-04-09T16:06:26.173Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/90/89ddba8e1c20b0922783cd93ed8e64f34dc05ab59c38a9c7e313632e20ff/librt-0.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9b3e3bc363f71bda1639a4ee593cb78f7fbfeacc73411ec0d4c92f00730010a4", size = 68332, upload-time = "2026-04-09T16:05:00.09Z" }, + { url = "https://files.pythonhosted.org/packages/a8/40/7aa4da1fb08bdeeb540cb07bfc8207cb32c5c41642f2594dbd0098a0662d/librt-0.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0a09c2f5869649101738653a9b7ab70cf045a1105ac66cbb8f4055e61df78f2d", size = 70581, upload-time = "2026-04-09T16:05:01.213Z" }, + { url = "https://files.pythonhosted.org/packages/48/ac/73a2187e1031041e93b7e3a25aae37aa6f13b838c550f7e0f06f66766212/librt-0.9.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:5ca8e133d799c948db2ab1afc081c333a825b5540475164726dcbf73537e5c2f", size = 203984, upload-time = "2026-04-09T16:05:02.542Z" }, + { url = "https://files.pythonhosted.org/packages/5e/3d/23460d571e9cbddb405b017681df04c142fb1b04cbfce77c54b08e28b108/librt-0.9.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:603138ee838ee1583f1b960b62d5d0007845c5c423feb68e44648b1359014e27", size = 215762, upload-time = "2026-04-09T16:05:04.127Z" }, + { url = "https://files.pythonhosted.org/packages/de/1e/42dc7f8ab63e65b20640d058e63e97fd3e482c1edbda3570d813b4d0b927/librt-0.9.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4003f70c56a5addd6aa0897f200dd59afd3bf7bcd5b3cce46dd21f925743bc2", size = 230288, upload-time = "2026-04-09T16:05:05.883Z" }, + { url = "https://files.pythonhosted.org/packages/dc/08/ca812b6d8259ad9ece703397f8ad5c03af5b5fedfce64279693d3ce4087c/librt-0.9.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:78042f6facfd98ecb25e9829c7e37cce23363d9d7c83bc5f72702c5059eb082b", size = 224103, upload-time = "2026-04-09T16:05:07.148Z" }, + { url = "https://files.pythonhosted.org/packages/b6/3f/620490fb2fa66ffd44e7f900254bc110ebec8dac6c1b7514d64662570e6f/librt-0.9.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a361c9434a64d70a7dbb771d1de302c0cc9f13c0bffe1cf7e642152814b35265", size = 232122, upload-time = "2026-04-09T16:05:08.386Z" }, + { url = "https://files.pythonhosted.org/packages/e9/83/12864700a1b6a8be458cf5d05db209b0d8e94ae281e7ec261dbe616597b4/librt-0.9.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:dd2c7e082b0b92e1baa4da28163a808672485617bc855cc22a2fd06978fa9084", size = 225045, upload-time = "2026-04-09T16:05:09.707Z" }, + { url = "https://files.pythonhosted.org/packages/fd/1b/845d339c29dc7dbc87a2e992a1ba8d28d25d0e0372f9a0a2ecebde298186/librt-0.9.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:7e6274fd33fc5b2a14d41c9119629d3ff395849d8bcbc80cf637d9e8d2034da8", size = 227372, upload-time = "2026-04-09T16:05:10.942Z" }, + { url = "https://files.pythonhosted.org/packages/8d/fe/277985610269d926a64c606f761d58d3db67b956dbbf40024921e95e7fcb/librt-0.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5093043afb226ecfa1400120d1ebd4442b4f99977783e4f4f7248879009b227f", size = 248224, upload-time = "2026-04-09T16:05:12.254Z" }, + { url = "https://files.pythonhosted.org/packages/92/1b/ee486d244b8de6b8b5dbaefabe6bfdd4a72e08f6353edf7d16d27114da8d/librt-0.9.0-cp312-cp312-win32.whl", hash = "sha256:9edcc35d1cae9fd5320171b1a838c7da8a5c968af31e82ecc3dff30b4be0957f", size = 55986, upload-time = "2026-04-09T16:05:13.529Z" }, + { url = "https://files.pythonhosted.org/packages/89/7a/ba1737012308c17dc6d5516143b5dce9a2c7ba3474afd54e11f44a4d1ef3/librt-0.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:3cc2917258e131ae5f958a4d872e07555b51cb7466a43433218061c74ef33745", size = 63260, upload-time = "2026-04-09T16:05:14.68Z" }, + { url = "https://files.pythonhosted.org/packages/36/e4/01752c113da15127f18f7bf11142f5640038f062407a611c059d0036c6aa/librt-0.9.0-cp312-cp312-win_arm64.whl", hash = "sha256:90e6d5420fc8a300518d4d2288154ff45005e920425c22cbbfe8330f3f754bd9", size = 53694, upload-time = "2026-04-09T16:05:16.095Z" }, + { url = "https://files.pythonhosted.org/packages/5f/d7/1b3e26fffde1452d82f5666164858a81c26ebe808e7ae8c9c88628981540/librt-0.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f29b68cd9714531672db62cc54f6e8ff981900f824d13fa0e00749189e13778e", size = 68367, upload-time = "2026-04-09T16:05:17.243Z" }, + { url = "https://files.pythonhosted.org/packages/a5/5b/c61b043ad2e091fbe1f2d35d14795e545d0b56b03edaa390fa1dcee3d160/librt-0.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7d5c8a5929ac325729f6119802070b561f4db793dffc45e9ac750992a4ed4d22", size = 70595, upload-time = "2026-04-09T16:05:18.471Z" }, + { url = "https://files.pythonhosted.org/packages/a3/22/2448471196d8a73370aa2f23445455dc42712c21404081fcd7a03b9e0749/librt-0.9.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:756775d25ec8345b837ab52effee3ad2f3b2dfd6bbee3e3f029c517bd5d8f05a", size = 204354, upload-time = "2026-04-09T16:05:19.593Z" }, + { url = "https://files.pythonhosted.org/packages/ac/5e/39fc4b153c78cfd2c8a2dcb32700f2d41d2312aa1050513183be4540930d/librt-0.9.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b8f5d00b49818f4e2b1667db994488b045835e0ac16fe2f924f3871bd2b8ac5", size = 216238, upload-time = "2026-04-09T16:05:20.868Z" }, + { url = "https://files.pythonhosted.org/packages/d7/42/bc2d02d0fa7badfa63aa8d6dcd8793a9f7ef5a94396801684a51ed8d8287/librt-0.9.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c81aef782380f0f13ead670aae01825eb653b44b046aa0e5ebbb79f76ed4aa11", size = 230589, upload-time = "2026-04-09T16:05:22.305Z" }, + { url = "https://files.pythonhosted.org/packages/c8/7b/e2d95cc513866373692aa5edf98080d5602dd07cabfb9e5d2f70df2f25f7/librt-0.9.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66b58fed90a545328e80d575467244de3741e088c1af928f0b489ebec3ef3858", size = 224610, upload-time = "2026-04-09T16:05:23.647Z" }, + { url = "https://files.pythonhosted.org/packages/31/d5/6cec4607e998eaba57564d06a1295c21b0a0c8de76e4e74d699e627bd98c/librt-0.9.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e78fb7419e07d98c2af4b8567b72b3eaf8cb05caad642e9963465569c8b2d87e", size = 232558, upload-time = "2026-04-09T16:05:25.025Z" }, + { url = "https://files.pythonhosted.org/packages/95/8c/27f1d8d3aaf079d3eb26439bf0b32f1482340c3552e324f7db9dca858671/librt-0.9.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c3786f0f4490a5cd87f1ed6cefae833ad6b1060d52044ce0434a2e85893afd0", size = 225521, upload-time = "2026-04-09T16:05:26.311Z" }, + { url = "https://files.pythonhosted.org/packages/6b/d8/1e0d43b1c329b416017619469b3c3801a25a6a4ef4a1c68332aeaa6f72ca/librt-0.9.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:8494cfc61e03542f2d381e71804990b3931175a29b9278fdb4a5459948778dc2", size = 227789, upload-time = "2026-04-09T16:05:27.624Z" }, + { url = "https://files.pythonhosted.org/packages/2c/b4/d3d842e88610fcd4c8eec7067b0c23ef2d7d3bff31496eded6a83b0f99be/librt-0.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:07cf11f769831186eeac424376e6189f20ace4f7263e2134bdb9757340d84d4d", size = 248616, upload-time = "2026-04-09T16:05:29.181Z" }, + { url = "https://files.pythonhosted.org/packages/ec/28/527df8ad0d1eb6c8bdfa82fc190f1f7c4cca5a1b6d7b36aeabf95b52d74d/librt-0.9.0-cp313-cp313-win32.whl", hash = "sha256:850d6d03177e52700af605fd60db7f37dcb89782049a149674d1a9649c2138fd", size = 56039, upload-time = "2026-04-09T16:05:30.709Z" }, + { url = "https://files.pythonhosted.org/packages/f3/a7/413652ad0d92273ee5e30c000fc494b361171177c83e57c060ecd3c21538/librt-0.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:a5af136bfba820d592f86c67affcef9b3ff4d4360ac3255e341e964489b48519", size = 63264, upload-time = "2026-04-09T16:05:31.881Z" }, + { url = "https://files.pythonhosted.org/packages/a4/0a/92c244309b774e290ddb15e93363846ae7aa753d9586b8aad511c5e6145b/librt-0.9.0-cp313-cp313-win_arm64.whl", hash = "sha256:4c4d0440a3a8e31d962340c3e1cc3fc9ee7febd34c8d8f770d06adb947779ea5", size = 53728, upload-time = "2026-04-09T16:05:33.31Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c1/184e539543f06ea2912f4b92a5ffaede4f9b392689e3f00acbf8134bee92/librt-0.9.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:3f05d145df35dca5056a8bc3838e940efebd893a54b3e19b2dda39ceaa299bcb", size = 67830, upload-time = "2026-04-09T16:05:34.517Z" }, + { url = "https://files.pythonhosted.org/packages/f3/ad/23399bdcb7afca819acacdef31b37ee59de261bd66b503a7995c03c4b0dc/librt-0.9.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1c587494461ebd42229d0f1739f3aa34237dd9980623ecf1be8d3bcba79f4499", size = 70280, upload-time = "2026-04-09T16:05:35.649Z" }, + { url = "https://files.pythonhosted.org/packages/9f/0b/4542dc5a2b8772dbf92cafb9194701230157e73c14b017b6961a23598b03/librt-0.9.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0a2040f801406b93657a70b72fa12311063a319fee72ce98e1524da7200171f", size = 201925, upload-time = "2026-04-09T16:05:36.739Z" }, + { url = "https://files.pythonhosted.org/packages/31/d4/8ee7358b08fd0cfce051ef96695380f09b3c2c11b77c9bfbc367c921cce5/librt-0.9.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f38bc489037eca88d6ebefc9c4d41a4e07c8e8b4de5188a9e6d290273ad7ebb1", size = 212381, upload-time = "2026-04-09T16:05:38.043Z" }, + { url = "https://files.pythonhosted.org/packages/f2/94/a2025fe442abedf8b038038dab3dba942009ad42b38ea064a1a9e6094241/librt-0.9.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3fd278f5e6bf7c75ccd6d12344eb686cc020712683363b66f46ac79d37c799f", size = 227065, upload-time = "2026-04-09T16:05:39.394Z" }, + { url = "https://files.pythonhosted.org/packages/7c/e9/b9fcf6afa909f957cfbbf918802f9dada1bd5d3c1da43d722fd6a310dc3f/librt-0.9.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fcbdf2a9ca24e87bbebb47f1fe34e531ef06f104f98c9ccfc953a3f3344c567a", size = 221333, upload-time = "2026-04-09T16:05:40.999Z" }, + { url = "https://files.pythonhosted.org/packages/ac/7c/ba54cd6aa6a3c8cd12757a6870e0c79a64b1e6327f5248dcff98423f4d43/librt-0.9.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e306d956cfa027fe041585f02a1602c32bfa6bb8ebea4899d373383295a6c62f", size = 229051, upload-time = "2026-04-09T16:05:42.605Z" }, + { url = "https://files.pythonhosted.org/packages/4b/4b/8cfdbad314c8677a0148bf0b70591d6d18587f9884d930276098a235461b/librt-0.9.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:465814ab157986acb9dfa5ccd7df944be5eefc0d08d31ec6e8d88bc71251d845", size = 222492, upload-time = "2026-04-09T16:05:43.842Z" }, + { url = "https://files.pythonhosted.org/packages/1f/d1/2eda69563a1a88706808decdce035e4b32755dbfbb0d05e1a65db9547ed1/librt-0.9.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:703f4ae36d6240bfe24f542bac784c7e4194ec49c3ba5a994d02891649e2d85b", size = 223849, upload-time = "2026-04-09T16:05:45.054Z" }, + { url = "https://files.pythonhosted.org/packages/04/44/b2ed37df6be5b3d42cfe36318e0598e80843d5c6308dd63d0bf4e0ce5028/librt-0.9.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3be322a15ee5e70b93b7a59cfd074614f22cc8c9ff18bd27f474e79137ea8d3b", size = 245001, upload-time = "2026-04-09T16:05:46.34Z" }, + { url = "https://files.pythonhosted.org/packages/47/e7/617e412426df89169dd2a9ed0cc8752d5763336252c65dbf945199915119/librt-0.9.0-cp314-cp314-win32.whl", hash = "sha256:b8da9f8035bb417770b1e1610526d87ad4fc58a2804dc4d79c53f6d2cf5a6eb9", size = 51799, upload-time = "2026-04-09T16:05:47.738Z" }, + { url = "https://files.pythonhosted.org/packages/24/ed/c22ca4db0ca3cbc285e4d9206108746beda561a9792289c3c31281d7e9df/librt-0.9.0-cp314-cp314-win_amd64.whl", hash = "sha256:b8bd70d5d816566a580d193326912f4a76ec2d28a97dc4cd4cc831c0af8e330e", size = 59165, upload-time = "2026-04-09T16:05:49.198Z" }, + { url = "https://files.pythonhosted.org/packages/24/56/875398fafa4cbc8f15b89366fc3287304ddd3314d861f182a4b87595ace0/librt-0.9.0-cp314-cp314-win_arm64.whl", hash = "sha256:fc5758e2b7a56532dc33e3c544d78cbaa9ecf0a0f2a2da2df882c1d6b99a317f", size = 49292, upload-time = "2026-04-09T16:05:50.362Z" }, + { url = "https://files.pythonhosted.org/packages/4c/61/bc448ecbf9b2d69c5cff88fe41496b19ab2a1cbda0065e47d4d0d51c0867/librt-0.9.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:f24b90b0e0c8cc9491fb1693ae91fe17cb7963153a1946395acdbdd5818429a4", size = 70175, upload-time = "2026-04-09T16:05:51.564Z" }, + { url = "https://files.pythonhosted.org/packages/60/f2/c47bb71069a73e2f04e70acbd196c1e5cc411578ac99039a224b98920fd4/librt-0.9.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3fe56e80badb66fdcde06bef81bbaa5bfcf6fbd7aefb86222d9e369c38c6b228", size = 72951, upload-time = "2026-04-09T16:05:52.699Z" }, + { url = "https://files.pythonhosted.org/packages/29/19/0549df59060631732df758e8886d92088da5fdbedb35b80e4643664e8412/librt-0.9.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:527b5b820b47a09e09829051452bb0d1dd2122261254e2a6f674d12f1d793d54", size = 225864, upload-time = "2026-04-09T16:05:53.895Z" }, + { url = "https://files.pythonhosted.org/packages/9d/f8/3b144396d302ac08e50f89e64452c38db84bc7b23f6c60479c5d3abd303c/librt-0.9.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d429bdd4ac0ab17c8e4a8af0ed2a7440b16eba474909ab357131018fe8c7e71", size = 241155, upload-time = "2026-04-09T16:05:55.191Z" }, + { url = "https://files.pythonhosted.org/packages/7a/ce/ee67ec14581de4043e61d05786d2aed6c9b5338816b7859bcf07455c6a9f/librt-0.9.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7202bdcac47d3a708271c4304a474a8605a4a9a4a709e954bf2d3241140aa938", size = 252235, upload-time = "2026-04-09T16:05:56.549Z" }, + { url = "https://files.pythonhosted.org/packages/8a/fa/0ead15daa2b293a54101550b08d4bafe387b7d4a9fc6d2b985602bae69b6/librt-0.9.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0d620e74897f8c2613b3c4e2e9c1e422eb46d2ddd07df540784d44117836af3", size = 244963, upload-time = "2026-04-09T16:05:57.858Z" }, + { url = "https://files.pythonhosted.org/packages/29/68/9fbf9a9aa704ba87689e40017e720aced8d9a4d2b46b82451d8142f91ec9/librt-0.9.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:d69fc39e627908f4c03297d5a88d9284b73f4d90b424461e32e8c2485e21c283", size = 257364, upload-time = "2026-04-09T16:05:59.686Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8d/9d60869f1b6716c762e45f66ed945b1e5dd649f7377684c3b176ae424648/librt-0.9.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:c2640e23d2b7c98796f123ffd95cf2022c7777aa8a4a3b98b36c570d37e85eee", size = 247661, upload-time = "2026-04-09T16:06:00.938Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/a5c365093962310bfdb4f6af256f191085078ffb529b3f0cbebb5b33ebe2/librt-0.9.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:451daa98463b7695b0a30aa56bf637831ea559e7b8101ac2ef6382e8eb15e29c", size = 248238, upload-time = "2026-04-09T16:06:02.537Z" }, + { url = "https://files.pythonhosted.org/packages/a0/3c/2d34365177f412c9e19c0a29f969d70f5343f27634b76b765a54d8b27705/librt-0.9.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:928bd06eca2c2bbf4349e5b817f837509b0604342e65a502de1d50a7570afd15", size = 269457, upload-time = "2026-04-09T16:06:03.833Z" }, + { url = "https://files.pythonhosted.org/packages/bc/cd/de45b239ea3bdf626f982a00c14bfcf2e12d261c510ba7db62c5969a27cd/librt-0.9.0-cp314-cp314t-win32.whl", hash = "sha256:a9c63e04d003bc0fb6a03b348018b9a3002f98268200e22cc80f146beac5dc40", size = 52453, upload-time = "2026-04-09T16:06:05.229Z" }, + { url = "https://files.pythonhosted.org/packages/7f/f9/bfb32ae428aa75c0c533915622176f0a17d6da7b72b5a3c6363685914f70/librt-0.9.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f162af66a2ed3f7d1d161a82ca584efd15acd9c1cff190a373458c32f7d42118", size = 60044, upload-time = "2026-04-09T16:06:06.398Z" }, + { url = "https://files.pythonhosted.org/packages/aa/47/7d70414bcdbb3bc1f458a8d10558f00bbfdb24e5a11740fc8197e12c3255/librt-0.9.0-cp314-cp314t-win_arm64.whl", hash = "sha256:a4b25c6c25cac5d0d9d6d6da855195b254e0021e513e0249f0e3b444dc6e0e61", size = 50009, upload-time = "2026-04-09T16:06:07.995Z" }, ] [[package]] @@ -1080,41 +1360,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] -[[package]] -name = "meshpy" -version = "2025.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b0/4a/4b75a61f083302301544c5d9ceb0813e7edac8cc9f4628fe9165e663a11b/meshpy-2025.1.1.tar.gz", hash = "sha256:70fc707fe9ccd9e907b95a9271804b4dd02e77d60644f64a0384cbf9e6d5b86b", size = 485344, upload-time = "2025-03-18T23:06:09.372Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/0d/887f98f597671ecc0476e188c94f592073fec95ad3d8c76f0728ef38a9db/meshpy-2025.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:547365a8f4df0bb72031f8361071133b28c9214ae5c5fd336fa1b2643aa7cc54", size = 525245, upload-time = "2025-03-18T23:05:43.664Z" }, - { url = "https://files.pythonhosted.org/packages/22/05/28b54af580d4f2305d3a78f9a24dc0d985bf4c2f790f77abd51d6399bc3b/meshpy-2025.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:af7334576b8336240c1ec12e84c3d6d024fe4233d8af565f95a60a68ffff6fdc", size = 472219, upload-time = "2025-03-18T23:05:45.067Z" }, - { url = "https://files.pythonhosted.org/packages/40/f1/a67d5c40f40a292f11d3ace41af1bc08b5aa84c4fef0e7c76673ace4b48e/meshpy-2025.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a41b4349a87468fa4883f9809e90201e0c9ba6f6d607a6131819ac581e5549", size = 595333, upload-time = "2025-03-18T23:05:46.358Z" }, - { url = "https://files.pythonhosted.org/packages/2d/bf/ea689f6ee156334b6f70e324ce60808b527ce1270e11ecaf807a5c472e76/meshpy-2025.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a64c724d8121d8bdf32d0e4b763bd7a9b7d49d84c1911c4e50fb43a1fa4ee4fc", size = 1627410, upload-time = "2025-03-18T23:05:48.069Z" }, - { url = "https://files.pythonhosted.org/packages/f6/6c/bf85fe98e4835f4353c6a7b14fb627167ebf596173eab9384be6a0f456f3/meshpy-2025.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:581d6360841b9fb337bd97e9471c721c333ecf85d882d16baa648d3baede5703", size = 603670, upload-time = "2025-03-18T23:05:49.539Z" }, - { url = "https://files.pythonhosted.org/packages/f9/03/00752cf2ea82f4445ed49f071a14ea559bdd3eb6bf51992233bed014f805/meshpy-2025.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a8f401ce316bdc0bb43677f0bd8a30bca274c5ce0d8693ca62fdef032a26da8", size = 525344, upload-time = "2025-03-18T23:05:50.812Z" }, - { url = "https://files.pythonhosted.org/packages/cd/80/8d555d8a9788182a61b8ebb79645d4bed230daa40ec75097dac3f563316b/meshpy-2025.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:606519dc602150f9460ac8e884a7a91e2f7b881df75c852db5d857c754a67ba1", size = 472212, upload-time = "2025-03-18T23:05:52.502Z" }, - { url = "https://files.pythonhosted.org/packages/a4/0a/e134f4925650b9b13d91a9a0f2021fd838df0fa45fdb2b49187425375e43/meshpy-2025.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8e0d12f4f784f40d616cbaf2b7bca2b2af7687e899aa831ddbf3f987cf8a03f", size = 595403, upload-time = "2025-03-18T23:05:53.998Z" }, - { url = "https://files.pythonhosted.org/packages/dd/f9/de3661faf70bcb0d525daf9e2a5c37cd32e2d7cc2c8da1f37b399109b040/meshpy-2025.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1fd5e34a4a52a313f1b052f3bc341ab8aaf0fd4cdb276ae2937443643988532f", size = 1627583, upload-time = "2025-03-18T23:05:55.693Z" }, - { url = "https://files.pythonhosted.org/packages/f9/59/281a98f7e184ec1c0410a5e427954855c74709e06cfc11fc885f829909f3/meshpy-2025.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:4a45fc1183c199f3aebfce99624e6c12297939bdea101f7358ac8cfd093ab0cf", size = 604581, upload-time = "2025-03-18T23:05:57.034Z" }, -] - [[package]] name = "moviepy" -version = "1.0.3" +version = "2.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "decorator" }, { name = "imageio" }, { name = "imageio-ffmpeg" }, { name = "numpy" }, + { name = "pillow" }, { name = "proglog" }, - { name = "requests" }, - { name = "tqdm" }, + { name = "python-dotenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/61/15f9476e270f64c78a834e7459ca045d669f869cec24eed26807b8cd479d/moviepy-2.2.1.tar.gz", hash = "sha256:c80cb56815ece94e5e3e2d361aa40070eeb30a09d23a24c4e684d03e16deacb1", size = 58431438, upload-time = "2025-05-21T19:31:52.601Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/73/7d3b2010baa0b5eb1e4dfa9e4385e89b6716be76f2fa21a6c0fe34b68e5a/moviepy-2.2.1-py3-none-any.whl", hash = "sha256:6b56803fec2ac54b557404126ac1160e65448e03798fa282bd23e8fab3795060", size = 129871, upload-time = "2025-05-21T19:31:50.11Z" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/18/54/01a8c4e35c75ca9724d19a7e4de9dc23f0ceb8769102c7de056113af61c3/moviepy-1.0.3.tar.gz", hash = "sha256:2884e35d1788077db3ff89e763c5ba7bfddbd7ae9108c9bc809e7ba58fa433f5", size = 388311, upload-time = "2020-05-07T16:27:46.856Z" } [[package]] name = "msgpack" @@ -1175,7 +1437,7 @@ wheels = [ [[package]] name = "mypy" -version = "1.19.1" +version = "1.20.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, @@ -1183,27 +1445,37 @@ dependencies = [ { name = "pathspec" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f5/db/4efed9504bc01309ab9c2da7e352cc223569f05478012b5d9ece38fd44d2/mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba", size = 3582404, upload-time = "2025-12-15T05:03:48.42Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/06/8a/19bfae96f6615aa8a0604915512e0289b1fad33d5909bf7244f02935d33a/mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1", size = 13206053, upload-time = "2025-12-15T05:03:46.622Z" }, - { url = "https://files.pythonhosted.org/packages/a5/34/3e63879ab041602154ba2a9f99817bb0c85c4df19a23a1443c8986e4d565/mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e", size = 12219134, upload-time = "2025-12-15T05:03:24.367Z" }, - { url = "https://files.pythonhosted.org/packages/89/cc/2db6f0e95366b630364e09845672dbee0cbf0bbe753a204b29a944967cd9/mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2", size = 12731616, upload-time = "2025-12-15T05:02:44.725Z" }, - { url = "https://files.pythonhosted.org/packages/00/be/dd56c1fd4807bc1eba1cf18b2a850d0de7bacb55e158755eb79f77c41f8e/mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8", size = 13620847, upload-time = "2025-12-15T05:03:39.633Z" }, - { url = "https://files.pythonhosted.org/packages/6d/42/332951aae42b79329f743bf1da088cd75d8d4d9acc18fbcbd84f26c1af4e/mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a", size = 13834976, upload-time = "2025-12-15T05:03:08.786Z" }, - { url = "https://files.pythonhosted.org/packages/6f/63/e7493e5f90e1e085c562bb06e2eb32cae27c5057b9653348d38b47daaecc/mypy-1.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13", size = 10118104, upload-time = "2025-12-15T05:03:10.834Z" }, - { url = "https://files.pythonhosted.org/packages/de/9f/a6abae693f7a0c697dbb435aac52e958dc8da44e92e08ba88d2e42326176/mypy-1.19.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250", size = 13201927, upload-time = "2025-12-15T05:02:29.138Z" }, - { url = "https://files.pythonhosted.org/packages/9a/a4/45c35ccf6e1c65afc23a069f50e2c66f46bd3798cbe0d680c12d12935caa/mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b", size = 12206730, upload-time = "2025-12-15T05:03:01.325Z" }, - { url = "https://files.pythonhosted.org/packages/05/bb/cdcf89678e26b187650512620eec8368fded4cfd99cfcb431e4cdfd19dec/mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e", size = 12724581, upload-time = "2025-12-15T05:03:20.087Z" }, - { url = "https://files.pythonhosted.org/packages/d1/32/dd260d52babf67bad8e6770f8e1102021877ce0edea106e72df5626bb0ec/mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef", size = 13616252, upload-time = "2025-12-15T05:02:49.036Z" }, - { url = "https://files.pythonhosted.org/packages/71/d0/5e60a9d2e3bd48432ae2b454b7ef2b62a960ab51292b1eda2a95edd78198/mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75", size = 13840848, upload-time = "2025-12-15T05:02:55.95Z" }, - { url = "https://files.pythonhosted.org/packages/98/76/d32051fa65ecf6cc8c6610956473abdc9b4c43301107476ac03559507843/mypy-1.19.1-cp313-cp313-win_amd64.whl", hash = "sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd", size = 10135510, upload-time = "2025-12-15T05:02:58.438Z" }, - { url = "https://files.pythonhosted.org/packages/de/eb/b83e75f4c820c4247a58580ef86fcd35165028f191e7e1ba57128c52782d/mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1", size = 13199744, upload-time = "2025-12-15T05:03:30.823Z" }, - { url = "https://files.pythonhosted.org/packages/94/28/52785ab7bfa165f87fcbb61547a93f98bb20e7f82f90f165a1f69bce7b3d/mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718", size = 12215815, upload-time = "2025-12-15T05:02:42.323Z" }, - { url = "https://files.pythonhosted.org/packages/0a/c6/bdd60774a0dbfb05122e3e925f2e9e846c009e479dcec4821dad881f5b52/mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b", size = 12740047, upload-time = "2025-12-15T05:03:33.168Z" }, - { url = "https://files.pythonhosted.org/packages/32/2a/66ba933fe6c76bd40d1fe916a83f04fed253152f451a877520b3c4a5e41e/mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045", size = 13601998, upload-time = "2025-12-15T05:03:13.056Z" }, - { url = "https://files.pythonhosted.org/packages/e3/da/5055c63e377c5c2418760411fd6a63ee2b96cf95397259038756c042574f/mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957", size = 13807476, upload-time = "2025-12-15T05:03:17.977Z" }, - { url = "https://files.pythonhosted.org/packages/cd/09/4ebd873390a063176f06b0dbf1f7783dd87bd120eae7727fa4ae4179b685/mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f", size = 10281872, upload-time = "2025-12-15T05:03:05.549Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f4/4ce9a05ce5ded1de3ec1c1d96cf9f9504a04e54ce0ed55cfa38619a32b8d/mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247", size = 2471239, upload-time = "2025-12-15T05:03:07.248Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/0b/3d/5b373635b3146264eb7a68d09e5ca11c305bbb058dfffbb47c47daf4f632/mypy-1.20.1.tar.gz", hash = "sha256:6fc3f4ecd52de81648fed1945498bf42fa2993ddfad67c9056df36ae5757f804", size = 3815892, upload-time = "2026-04-13T02:46:51.474Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/1b/75a7c825a02781ca10bc2f2f12fba2af5202f6d6005aad8d2d1f264d8d78/mypy-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:36ee2b9c6599c230fea89bbd79f401f9f9f8e9fcf0c777827789b19b7da90f51", size = 14494077, upload-time = "2026-04-13T02:45:55.085Z" }, + { url = "https://files.pythonhosted.org/packages/b0/54/5e5a569ea5c2b4d48b729fb32aa936eeb4246e4fc3e6f5b3d36a2dfbefb9/mypy-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fba3fb0968a7b48806b0c90f38d39296f10766885a94c83bd21399de1e14eb28", size = 13319495, upload-time = "2026-04-13T02:45:29.674Z" }, + { url = "https://files.pythonhosted.org/packages/6f/a4/a1945b19f33e91721b59deee3abb484f2fa5922adc33bb166daf5325d76d/mypy-1.20.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef1415a637cd3627d6304dfbeddbadd21079dafc2a8a753c477ce4fc0c2af54f", size = 13696948, upload-time = "2026-04-13T02:46:15.006Z" }, + { url = "https://files.pythonhosted.org/packages/b2/c6/75e969781c2359b2f9c15b061f28ec6d67c8b61865ceda176e85c8e7f2de/mypy-1.20.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef3461b1ad5cd446e540016e90b5984657edda39f982f4cc45ca317b628f5a37", size = 14706744, upload-time = "2026-04-13T02:46:00.482Z" }, + { url = "https://files.pythonhosted.org/packages/a8/6e/b221b1de981fc4262fe3e0bf9ec272d292dfe42394a689c2d49765c144c4/mypy-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:542dd63c9e1339b6092eb25bd515f3a32a1453aee8c9521d2ddb17dacd840237", size = 14949035, upload-time = "2026-04-13T02:45:06.021Z" }, + { url = "https://files.pythonhosted.org/packages/ca/4b/298ba2de0aafc0da3ff2288da06884aae7ba6489bc247c933f87847c41b3/mypy-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:1d55c7cd8ca22e31f93af2a01160a9e95465b5878de23dba7e48116052f20a8d", size = 10883216, upload-time = "2026-04-13T02:45:47.232Z" }, + { url = "https://files.pythonhosted.org/packages/c7/f9/5e25b8f0b8cb92f080bfed9c21d3279b2a0b6a601cdca369a039ba84789d/mypy-1.20.1-cp312-cp312-win_arm64.whl", hash = "sha256:f5b84a79070586e0d353ee07b719d9d0a4aa7c8ee90c0ea97747e98cbe193019", size = 9814299, upload-time = "2026-04-13T02:45:21.934Z" }, + { url = "https://files.pythonhosted.org/packages/21/e8/ef0991aa24c8f225df10b034f3c2681213cb54cf247623c6dec9a5744e70/mypy-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f3886c03e40afefd327bd70b3f634b39ea82e87f314edaa4d0cce4b927ddcc1", size = 14500739, upload-time = "2026-04-13T02:46:05.442Z" }, + { url = "https://files.pythonhosted.org/packages/23/73/416ebec3047636ed89fa871dc8c54bf05e9e20aa9499da59790d7adb312d/mypy-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e860eb3904f9764e83bafd70c8250bdffdc7dde6b82f486e8156348bf7ceb184", size = 13314735, upload-time = "2026-04-13T02:46:47.154Z" }, + { url = "https://files.pythonhosted.org/packages/10/1e/1505022d9c9ac2e014a384eb17638fb37bf8e9d0a833ea60605b66f8f7ba/mypy-1.20.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a4b5aac6e785719da51a84f5d09e9e843d473170a9045b1ea7ea1af86225df4b", size = 13704356, upload-time = "2026-04-13T02:45:19.773Z" }, + { url = "https://files.pythonhosted.org/packages/98/91/275b01f5eba5c467a3318ec214dd865abb66e9c811231c8587287b92876a/mypy-1.20.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f37b6cd0fe2ad3a20f05ace48ca3523fc52ff86940e34937b439613b6854472e", size = 14696420, upload-time = "2026-04-13T02:45:24.205Z" }, + { url = "https://files.pythonhosted.org/packages/a1/57/b3779e134e1b7250d05f874252780d0a88c068bc054bcff99ca20a3a2986/mypy-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4bbb0f6b54ce7cc350ef4a770650d15fa70edd99ad5267e227133eda9c94218", size = 14936093, upload-time = "2026-04-13T02:45:32.087Z" }, + { url = "https://files.pythonhosted.org/packages/be/33/81b64991b0f3f278c3b55c335888794af190b2d59031a5ad1401bcb69f1e/mypy-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:c3dc20f8ec76eecd77148cdd2f1542ed496e51e185713bf488a414f862deb8f2", size = 10889659, upload-time = "2026-04-13T02:46:02.926Z" }, + { url = "https://files.pythonhosted.org/packages/1b/fd/7adcb8053572edf5ef8f3db59599dfeeee3be9cc4c8c97e2d28f66f42ac5/mypy-1.20.1-cp313-cp313-win_arm64.whl", hash = "sha256:a9d62bbac5d6d46718e2b0330b25e6264463ed832722b8f7d4440ff1be3ca895", size = 9815515, upload-time = "2026-04-13T02:46:32.103Z" }, + { url = "https://files.pythonhosted.org/packages/40/cd/db831e84c81d57d4886d99feee14e372f64bbec6a9cb1a88a19e243f2ef5/mypy-1.20.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:12927b9c0ed794daedcf1dab055b6c613d9d5659ac511e8d936d96f19c087d12", size = 14483064, upload-time = "2026-04-13T02:45:26.901Z" }, + { url = "https://files.pythonhosted.org/packages/d5/82/74e62e7097fa67da328ac8ece8de09133448c04d20ddeaeba251a3000f01/mypy-1.20.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:752507dd481e958b2c08fc966d3806c962af5a9433b5bf8f3bdd7175c20e34fe", size = 13335694, upload-time = "2026-04-13T02:46:12.514Z" }, + { url = "https://files.pythonhosted.org/packages/74/c4/97e9a0abe4f3cdbbf4d079cb87a03b786efeccf5bf2b89fe4f96939ab2e6/mypy-1.20.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c614655b5a065e56274c6cbbe405f7cf7e96c0654db7ba39bc680238837f7b08", size = 13726365, upload-time = "2026-04-13T02:45:17.422Z" }, + { url = "https://files.pythonhosted.org/packages/d7/aa/a19d884a8d28fcd3c065776323029f204dbc774e70ec9c85eba228b680de/mypy-1.20.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2c3f6221a76f34d5100c6d35b3ef6b947054123c3f8d6938a4ba00b1308aa572", size = 14693472, upload-time = "2026-04-13T02:46:41.253Z" }, + { url = "https://files.pythonhosted.org/packages/84/44/cc9324bd21cf786592b44bf3b5d224b3923c1230ec9898d508d00241d465/mypy-1.20.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4bdfc06303ac06500af71ea0cdbe995c502b3c9ba32f3f8313523c137a25d1b6", size = 14919266, upload-time = "2026-04-13T02:46:28.37Z" }, + { url = "https://files.pythonhosted.org/packages/6e/dc/779abb25a8c63e8f44bf5a336217fa92790fa17e0c40e0c725d10cb01bbd/mypy-1.20.1-cp314-cp314-win_amd64.whl", hash = "sha256:0131edd7eba289973d1ba1003d1a37c426b85cdef76650cd02da6420898a5eb3", size = 11049713, upload-time = "2026-04-13T02:45:57.673Z" }, + { url = "https://files.pythonhosted.org/packages/28/08/4172be2ad7de9119b5a92ca36abbf641afdc5cb1ef4ae0c3a8182f29674f/mypy-1.20.1-cp314-cp314-win_arm64.whl", hash = "sha256:33f02904feb2c07e1fdf7909026206396c9deeb9e6f34d466b4cfedb0aadbbe4", size = 9999819, upload-time = "2026-04-13T02:46:35.039Z" }, + { url = "https://files.pythonhosted.org/packages/2d/af/af9e46b0c8eabbce9fc04a477564170f47a1c22b308822282a59b7ff315f/mypy-1.20.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:168472149dd8cc505c98cefd21ad77e4257ed6022cd5ed2fe2999bed56977a5a", size = 15547508, upload-time = "2026-04-13T02:46:25.588Z" }, + { url = "https://files.pythonhosted.org/packages/a7/cd/39c9e4ad6ba33e069e5837d772a9e6c304b4a5452a14a975d52b36444650/mypy-1.20.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:eb674600309a8f22790cca883a97c90299f948183ebb210fbef6bcee07cb1986", size = 14399557, upload-time = "2026-04-13T02:46:10.021Z" }, + { url = "https://files.pythonhosted.org/packages/83/c1/3fd71bdc118ffc502bf57559c909927bb7e011f327f7bb8e0488e98a5870/mypy-1.20.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef2b2e4cc464ba9795459f2586923abd58a0055487cbe558cb538ea6e6bc142a", size = 15045789, upload-time = "2026-04-13T02:45:10.81Z" }, + { url = "https://files.pythonhosted.org/packages/8e/73/6f07ff8b57a7d7b3e6e5bf34685d17632382395c8bb53364ec331661f83e/mypy-1.20.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dee461d396dd46b3f0ed5a098dbc9b8860c81c46ad44fa071afcfbc149f167c9", size = 15850795, upload-time = "2026-04-13T02:45:03.349Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e2/f7dffec1c7767078f9e9adf0c786d1fe0ff30964a77eb213c09b8b58cb76/mypy-1.20.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e364926308b3e66f1361f81a566fc1b2f8cd47fc8525e8136d4058a65a4b4f02", size = 16088539, upload-time = "2026-04-13T02:46:17.841Z" }, + { url = "https://files.pythonhosted.org/packages/1a/76/e0dee71035316e75a69d73aec2f03c39c21c967b97e277fd0ef8fd6aec66/mypy-1.20.1-cp314-cp314t-win_amd64.whl", hash = "sha256:a0c17fbd746d38c70cbc42647cfd884f845a9708a4b160a8b4f7e70d41f4d7fa", size = 12575567, upload-time = "2026-04-13T02:45:34.795Z" }, + { url = "https://files.pythonhosted.org/packages/22/a8/7ed43c9d9c3d1468f86605e323a5d97e411a448790a00f07e779f3211a46/mypy-1.20.1-cp314-cp314t-win_arm64.whl", hash = "sha256:db2cb89654626a912efda69c0d5c1d22d948265e2069010d3dde3abf751c7d08", size = 10378823, upload-time = "2026-04-13T02:45:13.35Z" }, + { url = "https://files.pythonhosted.org/packages/d8/28/926bd972388e65a39ee98e188ccf67e81beb3aacfd5d6b310051772d974b/mypy-1.20.1-py3-none-any.whl", hash = "sha256:1aae28507f253fe82d883790d1c0a0d35798a810117c88184097fe8881052f06", size = 2636553, upload-time = "2026-04-13T02:46:30.45Z" }, ] [[package]] @@ -1263,6 +1535,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4d/20/28f669c09a470e7f523b0cc10b94336664d9648594015e3f2a1ec29047b1/ndindex-1.10.1-cp314-cp314t-win_amd64.whl", hash = "sha256:37f87f0e7690ae0324334740e0661d6297f2e62c9bf925127d249fb7eddd0ad8", size = 171077, upload-time = "2025-11-19T20:39:50.108Z" }, ] +[[package]] +name = "ntplib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b4/14/6b018fb602602d9f6cc7485cbad7c1be3a85d25cea18c233854f05284aed/ntplib-0.4.0.tar.gz", hash = "sha256:899d8fb5f8c2555213aea95efca02934c7343df6ace9d7628a5176b176906267", size = 7135, upload-time = "2021-05-28T19:08:54.394Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/8c/41da70f6feaca807357206a376b6de2001b439c7f78f53473a914a6dbd1e/ntplib-0.4.0-py2.py3-none-any.whl", hash = "sha256:8d27375329ed7ff38755f7b6d4658b28edc147cadf40338a63a0da8133469d60", size = 6849, upload-time = "2021-05-28T19:08:53.323Z" }, +] + +[[package]] +name = "numdifftools" +version = "0.9.42" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/17/94/7c83677dddc78f93230f4c8a6a5faa06c92699a76eb019386a3aed8a9762/numdifftools-0.9.42.tar.gz", hash = "sha256:866675171f293c4bf2f1e1c5bf9b88a07d5396903e3b3e7fcc3879e2a01cfbc1", size = 79612, upload-time = "2025-12-11T12:06:10.54Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/60/c7504633e9fe53dc823db5d83dc15651c595cf35d668781832b4d2748272/numdifftools-0.9.42-py3-none-any.whl", hash = "sha256:22f926b8de24aa44f740bc26744a74555c1c80413068b1dee2edb3c3d10566f6", size = 94252, upload-time = "2025-12-11T12:06:09.322Z" }, +] + [[package]] name = "numexpr" version = "2.14.1" @@ -1316,63 +1610,63 @@ wheels = [ [[package]] name = "numpy" -version = "2.4.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/10/8b/c265f4823726ab832de836cdd184d0986dcf94480f81e8739692a7ac7af2/numpy-2.4.3.tar.gz", hash = "sha256:483a201202b73495f00dbc83796c6ae63137a9bdade074f7648b3e32613412dd", size = 20727743, upload-time = "2026-03-09T07:58:53.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/ed/6388632536f9788cea23a3a1b629f25b43eaacd7d7377e5d6bc7b9deb69b/numpy-2.4.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:61b0cbabbb6126c8df63b9a3a0c4b1f44ebca5e12ff6997b80fcf267fb3150ef", size = 16669628, upload-time = "2026-03-09T07:56:24.252Z" }, - { url = "https://files.pythonhosted.org/packages/74/1b/ee2abfc68e1ce728b2958b6ba831d65c62e1b13ce3017c13943f8f9b5b2e/numpy-2.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7395e69ff32526710748f92cd8c9849b361830968ea3e24a676f272653e8983e", size = 14696872, upload-time = "2026-03-09T07:56:26.991Z" }, - { url = "https://files.pythonhosted.org/packages/ba/d1/780400e915ff5638166f11ca9dc2c5815189f3d7cf6f8759a1685e586413/numpy-2.4.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:abdce0f71dcb4a00e4e77f3faf05e4616ceccfe72ccaa07f47ee79cda3b7b0f4", size = 5203489, upload-time = "2026-03-09T07:56:29.414Z" }, - { url = "https://files.pythonhosted.org/packages/0b/bb/baffa907e9da4cc34a6e556d6d90e032f6d7a75ea47968ea92b4858826c4/numpy-2.4.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:48da3a4ee1336454b07497ff7ec83903efa5505792c4e6d9bf83d99dc07a1e18", size = 6550814, upload-time = "2026-03-09T07:56:32.225Z" }, - { url = "https://files.pythonhosted.org/packages/7b/12/8c9f0c6c95f76aeb20fc4a699c33e9f827fa0d0f857747c73bb7b17af945/numpy-2.4.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:32e3bef222ad6b052280311d1d60db8e259e4947052c3ae7dd6817451fc8a4c5", size = 15666601, upload-time = "2026-03-09T07:56:34.461Z" }, - { url = "https://files.pythonhosted.org/packages/bd/79/cc665495e4d57d0aa6fbcc0aa57aa82671dfc78fbf95fe733ed86d98f52a/numpy-2.4.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7dd01a46700b1967487141a66ac1a3cf0dd8ebf1f08db37d46389401512ca97", size = 16621358, upload-time = "2026-03-09T07:56:36.852Z" }, - { url = "https://files.pythonhosted.org/packages/a8/40/b4ecb7224af1065c3539f5ecfff879d090de09608ad1008f02c05c770cb3/numpy-2.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:76f0f283506c28b12bba319c0fab98217e9f9b54e6160e9c79e9f7348ba32e9c", size = 17016135, upload-time = "2026-03-09T07:56:39.337Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b1/6a88e888052eed951afed7a142dcdf3b149a030ca59b4c71eef085858e43/numpy-2.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:737f630a337364665aba3b5a77e56a68cc42d350edd010c345d65a3efa3addcc", size = 18345816, upload-time = "2026-03-09T07:56:42.31Z" }, - { url = "https://files.pythonhosted.org/packages/f3/8f/103a60c5f8c3d7fc678c19cd7b2476110da689ccb80bc18050efbaeae183/numpy-2.4.3-cp312-cp312-win32.whl", hash = "sha256:26952e18d82a1dbbc2f008d402021baa8d6fc8e84347a2072a25e08b46d698b9", size = 5960132, upload-time = "2026-03-09T07:56:44.851Z" }, - { url = "https://files.pythonhosted.org/packages/d7/7c/f5ee1bf6ed888494978046a809df2882aad35d414b622893322df7286879/numpy-2.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:65f3c2455188f09678355f5cae1f959a06b778bc66d535da07bf2ef20cd319d5", size = 12316144, upload-time = "2026-03-09T07:56:47.057Z" }, - { url = "https://files.pythonhosted.org/packages/71/46/8d1cb3f7a00f2fb6394140e7e6623696e54c6318a9d9691bb4904672cf42/numpy-2.4.3-cp312-cp312-win_arm64.whl", hash = "sha256:2abad5c7fef172b3377502bde47892439bae394a71bc329f31df0fd829b41a9e", size = 10220364, upload-time = "2026-03-09T07:56:49.849Z" }, - { url = "https://files.pythonhosted.org/packages/b6/d0/1fe47a98ce0df229238b77611340aff92d52691bcbc10583303181abf7fc/numpy-2.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b346845443716c8e542d54112966383b448f4a3ba5c66409771b8c0889485dd3", size = 16665297, upload-time = "2026-03-09T07:56:52.296Z" }, - { url = "https://files.pythonhosted.org/packages/27/d9/4e7c3f0e68dfa91f21c6fb6cf839bc829ec920688b1ce7ec722b1a6202fb/numpy-2.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2629289168f4897a3c4e23dc98d6f1731f0fc0fe52fb9db19f974041e4cc12b9", size = 14691853, upload-time = "2026-03-09T07:56:54.992Z" }, - { url = "https://files.pythonhosted.org/packages/3a/66/bd096b13a87549683812b53ab211e6d413497f84e794fb3c39191948da97/numpy-2.4.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:bb2e3cf95854233799013779216c57e153c1ee67a0bf92138acca0e429aefaee", size = 5198435, upload-time = "2026-03-09T07:56:57.184Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2f/687722910b5a5601de2135c891108f51dfc873d8e43c8ed9f4ebb440b4a2/numpy-2.4.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:7f3408ff897f8ab07a07fbe2823d7aee6ff644c097cc1f90382511fe982f647f", size = 6546347, upload-time = "2026-03-09T07:56:59.531Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ec/7971c4e98d86c564750393fab8d7d83d0a9432a9d78bb8a163a6dc59967a/numpy-2.4.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:decb0eb8a53c3b009b0962378065589685d66b23467ef5dac16cbe818afde27f", size = 15664626, upload-time = "2026-03-09T07:57:01.385Z" }, - { url = "https://files.pythonhosted.org/packages/7e/eb/7daecbea84ec935b7fc732e18f532073064a3816f0932a40a17f3349185f/numpy-2.4.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5f51900414fc9204a0e0da158ba2ac52b75656e7dce7e77fb9f84bfa343b4cc", size = 16608916, upload-time = "2026-03-09T07:57:04.008Z" }, - { url = "https://files.pythonhosted.org/packages/df/58/2a2b4a817ffd7472dca4421d9f0776898b364154e30c95f42195041dc03b/numpy-2.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6bd06731541f89cdc01b261ba2c9e037f1543df7472517836b78dfb15bd6e476", size = 17015824, upload-time = "2026-03-09T07:57:06.347Z" }, - { url = "https://files.pythonhosted.org/packages/4a/ca/627a828d44e78a418c55f82dd4caea8ea4a8ef24e5144d9e71016e52fb40/numpy-2.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:22654fe6be0e5206f553a9250762c653d3698e46686eee53b399ab90da59bd92", size = 18334581, upload-time = "2026-03-09T07:57:09.114Z" }, - { url = "https://files.pythonhosted.org/packages/cd/c0/76f93962fc79955fcba30a429b62304332345f22d4daec1cb33653425643/numpy-2.4.3-cp313-cp313-win32.whl", hash = "sha256:d71e379452a2f670ccb689ec801b1218cd3983e253105d6e83780967e899d687", size = 5958618, upload-time = "2026-03-09T07:57:11.432Z" }, - { url = "https://files.pythonhosted.org/packages/b1/3c/88af0040119209b9b5cb59485fa48b76f372c73068dbf9254784b975ac53/numpy-2.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:0a60e17a14d640f49146cb38e3f105f571318db7826d9b6fef7e4dce758faecd", size = 12312824, upload-time = "2026-03-09T07:57:13.586Z" }, - { url = "https://files.pythonhosted.org/packages/58/ce/3d07743aced3d173f877c3ef6a454c2174ba42b584ab0b7e6d99374f51ed/numpy-2.4.3-cp313-cp313-win_arm64.whl", hash = "sha256:c9619741e9da2059cd9c3f206110b97583c7152c1dc9f8aafd4beb450ac1c89d", size = 10221218, upload-time = "2026-03-09T07:57:16.183Z" }, - { url = "https://files.pythonhosted.org/packages/62/09/d96b02a91d09e9d97862f4fc8bfebf5400f567d8eb1fe4b0cc4795679c15/numpy-2.4.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7aa4e54f6469300ebca1d9eb80acd5253cdfa36f2c03d79a35883687da430875", size = 14819570, upload-time = "2026-03-09T07:57:18.564Z" }, - { url = "https://files.pythonhosted.org/packages/b5/ca/0b1aba3905fdfa3373d523b2b15b19029f4f3031c87f4066bd9d20ef6c6b/numpy-2.4.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d1b90d840b25874cf5cd20c219af10bac3667db3876d9a495609273ebe679070", size = 5326113, upload-time = "2026-03-09T07:57:21.052Z" }, - { url = "https://files.pythonhosted.org/packages/c0/63/406e0fd32fcaeb94180fd6a4c41e55736d676c54346b7efbce548b94a914/numpy-2.4.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a749547700de0a20a6718293396ec237bb38218049cfce788e08fcb716e8cf73", size = 6646370, upload-time = "2026-03-09T07:57:22.804Z" }, - { url = "https://files.pythonhosted.org/packages/b6/d0/10f7dc157d4b37af92720a196be6f54f889e90dcd30dce9dc657ed92c257/numpy-2.4.3-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94f3c4a151a2e529adf49c1d54f0f57ff8f9b233ee4d44af623a81553ab86368", size = 15723499, upload-time = "2026-03-09T07:57:24.693Z" }, - { url = "https://files.pythonhosted.org/packages/66/f1/d1c2bf1161396629701bc284d958dc1efa3a5a542aab83cf11ee6eb4cba5/numpy-2.4.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22c31dc07025123aedf7f2db9e91783df13f1776dc52c6b22c620870dc0fab22", size = 16657164, upload-time = "2026-03-09T07:57:27.676Z" }, - { url = "https://files.pythonhosted.org/packages/1a/be/cca19230b740af199ac47331a21c71e7a3d0ba59661350483c1600d28c37/numpy-2.4.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:148d59127ac95979d6f07e4d460f934ebdd6eed641db9c0db6c73026f2b2101a", size = 17081544, upload-time = "2026-03-09T07:57:30.664Z" }, - { url = "https://files.pythonhosted.org/packages/b9/c5/9602b0cbb703a0936fb40f8a95407e8171935b15846de2f0776e08af04c7/numpy-2.4.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a97cbf7e905c435865c2d939af3d93f99d18eaaa3cabe4256f4304fb51604349", size = 18380290, upload-time = "2026-03-09T07:57:33.763Z" }, - { url = "https://files.pythonhosted.org/packages/ed/81/9f24708953cd30be9ee36ec4778f4b112b45165812f2ada4cc5ea1c1f254/numpy-2.4.3-cp313-cp313t-win32.whl", hash = "sha256:be3b8487d725a77acccc9924f65fd8bce9af7fac8c9820df1049424a2115af6c", size = 6082814, upload-time = "2026-03-09T07:57:36.491Z" }, - { url = "https://files.pythonhosted.org/packages/e2/9e/52f6eaa13e1a799f0ab79066c17f7016a4a8ae0c1aefa58c82b4dab690b4/numpy-2.4.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1ec84fd7c8e652b0f4aaaf2e6e9cc8eaa9b1b80a537e06b2e3a2fb176eedcb26", size = 12452673, upload-time = "2026-03-09T07:57:38.281Z" }, - { url = "https://files.pythonhosted.org/packages/c4/04/b8cece6ead0b30c9fbd99bb835ad7ea0112ac5f39f069788c5558e3b1ab2/numpy-2.4.3-cp313-cp313t-win_arm64.whl", hash = "sha256:120df8c0a81ebbf5b9020c91439fccd85f5e018a927a39f624845be194a2be02", size = 10290907, upload-time = "2026-03-09T07:57:40.747Z" }, - { url = "https://files.pythonhosted.org/packages/70/ae/3936f79adebf8caf81bd7a599b90a561334a658be4dcc7b6329ebf4ee8de/numpy-2.4.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:5884ce5c7acfae1e4e1b6fde43797d10aa506074d25b531b4f54bde33c0c31d4", size = 16664563, upload-time = "2026-03-09T07:57:43.817Z" }, - { url = "https://files.pythonhosted.org/packages/9b/62/760f2b55866b496bb1fa7da2a6db076bef908110e568b02fcfc1422e2a3a/numpy-2.4.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:297837823f5bc572c5f9379b0c9f3a3365f08492cbdc33bcc3af174372ebb168", size = 14702161, upload-time = "2026-03-09T07:57:46.169Z" }, - { url = "https://files.pythonhosted.org/packages/32/af/a7a39464e2c0a21526fb4fb76e346fb172ebc92f6d1c7a07c2c139cc17b1/numpy-2.4.3-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:a111698b4a3f8dcbe54c64a7708f049355abd603e619013c346553c1fd4ca90b", size = 5208738, upload-time = "2026-03-09T07:57:48.506Z" }, - { url = "https://files.pythonhosted.org/packages/29/8c/2a0cf86a59558fa078d83805589c2de490f29ed4fb336c14313a161d358a/numpy-2.4.3-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:4bd4741a6a676770e0e97fe9ab2e51de01183df3dcbcec591d26d331a40de950", size = 6543618, upload-time = "2026-03-09T07:57:50.591Z" }, - { url = "https://files.pythonhosted.org/packages/aa/b8/612ce010c0728b1c363fa4ea3aa4c22fe1c5da1de008486f8c2f5cb92fae/numpy-2.4.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:54f29b877279d51e210e0c80709ee14ccbbad647810e8f3d375561c45ef613dd", size = 15680676, upload-time = "2026-03-09T07:57:52.34Z" }, - { url = "https://files.pythonhosted.org/packages/a9/7e/4f120ecc54ba26ddf3dc348eeb9eb063f421de65c05fc961941798feea18/numpy-2.4.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:679f2a834bae9020f81534671c56fd0cc76dd7e5182f57131478e23d0dc59e24", size = 16613492, upload-time = "2026-03-09T07:57:54.91Z" }, - { url = "https://files.pythonhosted.org/packages/2c/86/1b6020db73be330c4b45d5c6ee4295d59cfeef0e3ea323959d053e5a6909/numpy-2.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d84f0f881cb2225c2dfd7f78a10a5645d487a496c6668d6cc39f0f114164f3d0", size = 17031789, upload-time = "2026-03-09T07:57:57.641Z" }, - { url = "https://files.pythonhosted.org/packages/07/3a/3b90463bf41ebc21d1b7e06079f03070334374208c0f9a1f05e4ae8455e7/numpy-2.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d213c7e6e8d211888cc359bab7199670a00f5b82c0978b9d1c75baf1eddbeac0", size = 18339941, upload-time = "2026-03-09T07:58:00.577Z" }, - { url = "https://files.pythonhosted.org/packages/a8/74/6d736c4cd962259fd8bae9be27363eb4883a2f9069763747347544c2a487/numpy-2.4.3-cp314-cp314-win32.whl", hash = "sha256:52077feedeff7c76ed7c9f1a0428558e50825347b7545bbb8523da2cd55c547a", size = 6007503, upload-time = "2026-03-09T07:58:03.331Z" }, - { url = "https://files.pythonhosted.org/packages/48/39/c56ef87af669364356bb011922ef0734fc49dad51964568634c72a009488/numpy-2.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:0448e7f9caefb34b4b7dd2b77f21e8906e5d6f0365ad525f9f4f530b13df2afc", size = 12444915, upload-time = "2026-03-09T07:58:06.353Z" }, - { url = "https://files.pythonhosted.org/packages/9d/1f/ab8528e38d295fd349310807496fabb7cf9fe2e1f70b97bc20a483ea9d4a/numpy-2.4.3-cp314-cp314-win_arm64.whl", hash = "sha256:b44fd60341c4d9783039598efadd03617fa28d041fc37d22b62d08f2027fa0e7", size = 10494875, upload-time = "2026-03-09T07:58:08.734Z" }, - { url = "https://files.pythonhosted.org/packages/e6/ef/b7c35e4d5ef141b836658ab21a66d1a573e15b335b1d111d31f26c8ef80f/numpy-2.4.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0a195f4216be9305a73c0e91c9b026a35f2161237cf1c6de9b681637772ea657", size = 14822225, upload-time = "2026-03-09T07:58:11.034Z" }, - { url = "https://files.pythonhosted.org/packages/cd/8d/7730fa9278cf6648639946cc816e7cc89f0d891602584697923375f801ed/numpy-2.4.3-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:cd32fbacb9fd1bf041bf8e89e4576b6f00b895f06d00914820ae06a616bdfef7", size = 5328769, upload-time = "2026-03-09T07:58:13.67Z" }, - { url = "https://files.pythonhosted.org/packages/47/01/d2a137317c958b074d338807c1b6a383406cdf8b8e53b075d804cc3d211d/numpy-2.4.3-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:2e03c05abaee1f672e9d67bc858f300b5ccba1c21397211e8d77d98350972093", size = 6649461, upload-time = "2026-03-09T07:58:15.912Z" }, - { url = "https://files.pythonhosted.org/packages/5c/34/812ce12bc0f00272a4b0ec0d713cd237cb390666eb6206323d1cc9cedbb2/numpy-2.4.3-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d1ce23cce91fcea443320a9d0ece9b9305d4368875bab09538f7a5b4131938a", size = 15725809, upload-time = "2026-03-09T07:58:17.787Z" }, - { url = "https://files.pythonhosted.org/packages/25/c0/2aed473a4823e905e765fee3dc2cbf504bd3e68ccb1150fbdabd5c39f527/numpy-2.4.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c59020932feb24ed49ffd03704fbab89f22aa9c0d4b180ff45542fe8918f5611", size = 16655242, upload-time = "2026-03-09T07:58:20.476Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c8/7e052b2fc87aa0e86de23f20e2c42bd261c624748aa8efd2c78f7bb8d8c6/numpy-2.4.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9684823a78a6cd6ad7511fc5e25b07947d1d5b5e2812c93fe99d7d4195130720", size = 17080660, upload-time = "2026-03-09T07:58:23.067Z" }, - { url = "https://files.pythonhosted.org/packages/f3/3d/0876746044db2adcb11549f214d104f2e1be00f07a67edbb4e2812094847/numpy-2.4.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0200b25c687033316fb39f0ff4e3e690e8957a2c3c8d22499891ec58c37a3eb5", size = 18380384, upload-time = "2026-03-09T07:58:25.839Z" }, - { url = "https://files.pythonhosted.org/packages/07/12/8160bea39da3335737b10308df4f484235fd297f556745f13092aa039d3b/numpy-2.4.3-cp314-cp314t-win32.whl", hash = "sha256:5e10da9e93247e554bb1d22f8edc51847ddd7dde52d85ce31024c1b4312bfba0", size = 6154547, upload-time = "2026-03-09T07:58:28.289Z" }, - { url = "https://files.pythonhosted.org/packages/42/f3/76534f61f80d74cc9cdf2e570d3d4eeb92c2280a27c39b0aaf471eda7b48/numpy-2.4.3-cp314-cp314t-win_amd64.whl", hash = "sha256:45f003dbdffb997a03da2d1d0cb41fbd24a87507fb41605c0420a3db5bd4667b", size = 12633645, upload-time = "2026-03-09T07:58:30.384Z" }, - { url = "https://files.pythonhosted.org/packages/1f/b6/7c0d4334c15983cec7f92a69e8ce9b1e6f31857e5ee3a413ac424e6bd63d/numpy-2.4.3-cp314-cp314t-win_arm64.whl", hash = "sha256:4d382735cecd7bcf090172489a525cd7d4087bc331f7df9f60ddc9a296cf208e", size = 10565454, upload-time = "2026-03-09T07:58:33.031Z" }, +version = "2.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/9f/b8cef5bffa569759033adda9481211426f12f53299629b410340795c2514/numpy-2.4.4.tar.gz", hash = "sha256:2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0", size = 20731587, upload-time = "2026-03-29T13:22:01.298Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/05/32396bec30fb2263770ee910142f49c1476d08e8ad41abf8403806b520ce/numpy-2.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:15716cfef24d3a9762e3acdf87e27f58dc823d1348f765bbea6bef8c639bfa1b", size = 16689272, upload-time = "2026-03-29T13:18:49.223Z" }, + { url = "https://files.pythonhosted.org/packages/c5/f3/a983d28637bfcd763a9c7aafdb6d5c0ebf3d487d1e1459ffdb57e2f01117/numpy-2.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:23cbfd4c17357c81021f21540da84ee282b9c8fba38a03b7b9d09ba6b951421e", size = 14699573, upload-time = "2026-03-29T13:18:52.629Z" }, + { url = "https://files.pythonhosted.org/packages/9b/fd/e5ecca1e78c05106d98028114f5c00d3eddb41207686b2b7de3e477b0e22/numpy-2.4.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8b3b60bb7cba2c8c81837661c488637eee696f59a877788a396d33150c35d842", size = 5204782, upload-time = "2026-03-29T13:18:55.579Z" }, + { url = "https://files.pythonhosted.org/packages/de/2f/702a4594413c1a8632092beae8aba00f1d67947389369b3777aed783fdca/numpy-2.4.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:e4a010c27ff6f210ff4c6ef34394cd61470d01014439b192ec22552ee867f2a8", size = 6552038, upload-time = "2026-03-29T13:18:57.769Z" }, + { url = "https://files.pythonhosted.org/packages/7f/37/eed308a8f56cba4d1fdf467a4fc67ef4ff4bf1c888f5fc980481890104b1/numpy-2.4.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f9e75681b59ddaa5e659898085ae0eaea229d054f2ac0c7e563a62205a700121", size = 15670666, upload-time = "2026-03-29T13:19:00.341Z" }, + { url = "https://files.pythonhosted.org/packages/0a/0d/0e3ecece05b7a7e87ab9fb587855548da437a061326fff64a223b6dcb78a/numpy-2.4.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:81f4a14bee47aec54f883e0cad2d73986640c1590eb9bfaaba7ad17394481e6e", size = 16645480, upload-time = "2026-03-29T13:19:03.63Z" }, + { url = "https://files.pythonhosted.org/packages/34/49/f2312c154b82a286758ee2f1743336d50651f8b5195db18cdb63675ff649/numpy-2.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:62d6b0f03b694173f9fcb1fb317f7222fd0b0b103e784c6549f5e53a27718c44", size = 17020036, upload-time = "2026-03-29T13:19:07.428Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e9/736d17bd77f1b0ec4f9901aaec129c00d59f5d84d5e79bba540ef12c2330/numpy-2.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fbc356aae7adf9e6336d336b9c8111d390a05df88f1805573ebb0807bd06fd1d", size = 18368643, upload-time = "2026-03-29T13:19:10.775Z" }, + { url = "https://files.pythonhosted.org/packages/63/f6/d417977c5f519b17c8a5c3bc9e8304b0908b0e21136fe43bf628a1343914/numpy-2.4.4-cp312-cp312-win32.whl", hash = "sha256:0d35aea54ad1d420c812bfa0385c71cd7cc5bcf7c65fed95fc2cd02fe8c79827", size = 5961117, upload-time = "2026-03-29T13:19:13.464Z" }, + { url = "https://files.pythonhosted.org/packages/2d/5b/e1deebf88ff431b01b7406ca3583ab2bbb90972bbe1c568732e49c844f7e/numpy-2.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:b5f0362dc928a6ecd9db58868fca5e48485205e3855957bdedea308f8672ea4a", size = 12320584, upload-time = "2026-03-29T13:19:16.155Z" }, + { url = "https://files.pythonhosted.org/packages/58/89/e4e856ac82a68c3ed64486a544977d0e7bdd18b8da75b78a577ca31c4395/numpy-2.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:846300f379b5b12cc769334464656bc882e0735d27d9726568bc932fdc49d5ec", size = 10221450, upload-time = "2026-03-29T13:19:18.994Z" }, + { url = "https://files.pythonhosted.org/packages/14/1d/d0a583ce4fefcc3308806a749a536c201ed6b5ad6e1322e227ee4848979d/numpy-2.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:08f2e31ed5e6f04b118e49821397f12767934cfdd12a1ce86a058f91e004ee50", size = 16684933, upload-time = "2026-03-29T13:19:22.47Z" }, + { url = "https://files.pythonhosted.org/packages/c1/62/2b7a48fbb745d344742c0277f01286dead15f3f68e4f359fbfcf7b48f70f/numpy-2.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e823b8b6edc81e747526f70f71a9c0a07ac4e7ad13020aa736bb7c9d67196115", size = 14694532, upload-time = "2026-03-29T13:19:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/e5/87/499737bfba066b4a3bebff24a8f1c5b2dee410b209bc6668c9be692580f0/numpy-2.4.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4a19d9dba1a76618dd86b164d608566f393f8ec6ac7c44f0cc879011c45e65af", size = 5199661, upload-time = "2026-03-29T13:19:28.31Z" }, + { url = "https://files.pythonhosted.org/packages/cd/da/464d551604320d1491bc345efed99b4b7034143a85787aab78d5691d5a0e/numpy-2.4.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:d2a8490669bfe99a233298348acc2d824d496dee0e66e31b66a6022c2ad74a5c", size = 6547539, upload-time = "2026-03-29T13:19:30.97Z" }, + { url = "https://files.pythonhosted.org/packages/7d/90/8d23e3b0dafd024bf31bdec225b3bb5c2dbfa6912f8a53b8659f21216cbf/numpy-2.4.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45dbed2ab436a9e826e302fcdcbe9133f9b0006e5af7168afb8963a6520da103", size = 15668806, upload-time = "2026-03-29T13:19:33.887Z" }, + { url = "https://files.pythonhosted.org/packages/d1/73/a9d864e42a01896bb5974475438f16086be9ba1f0d19d0bb7a07427c4a8b/numpy-2.4.4-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c901b15172510173f5cb310eae652908340f8dede90fff9e3bf6c0d8dfd92f83", size = 16632682, upload-time = "2026-03-29T13:19:37.336Z" }, + { url = "https://files.pythonhosted.org/packages/34/fb/14570d65c3bde4e202a031210475ae9cde9b7686a2e7dc97ee67d2833b35/numpy-2.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:99d838547ace2c4aace6c4f76e879ddfe02bb58a80c1549928477862b7a6d6ed", size = 17019810, upload-time = "2026-03-29T13:19:40.963Z" }, + { url = "https://files.pythonhosted.org/packages/8a/77/2ba9d87081fd41f6d640c83f26fb7351e536b7ce6dd9061b6af5904e8e46/numpy-2.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0aec54fd785890ecca25a6003fd9a5aed47ad607bbac5cd64f836ad8666f4959", size = 18357394, upload-time = "2026-03-29T13:19:44.859Z" }, + { url = "https://files.pythonhosted.org/packages/a2/23/52666c9a41708b0853fa3b1a12c90da38c507a3074883823126d4e9d5b30/numpy-2.4.4-cp313-cp313-win32.whl", hash = "sha256:07077278157d02f65c43b1b26a3886bce886f95d20aabd11f87932750dfb14ed", size = 5959556, upload-time = "2026-03-29T13:19:47.661Z" }, + { url = "https://files.pythonhosted.org/packages/57/fb/48649b4971cde70d817cf97a2a2fdc0b4d8308569f1dd2f2611959d2e0cf/numpy-2.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:5c70f1cc1c4efbe316a572e2d8b9b9cc44e89b95f79ca3331553fbb63716e2bf", size = 12317311, upload-time = "2026-03-29T13:19:50.67Z" }, + { url = "https://files.pythonhosted.org/packages/ba/d8/11490cddd564eb4de97b4579ef6bfe6a736cc07e94c1598590ae25415e01/numpy-2.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:ef4059d6e5152fa1a39f888e344c73fdc926e1b2dd58c771d67b0acfbf2aa67d", size = 10222060, upload-time = "2026-03-29T13:19:54.229Z" }, + { url = "https://files.pythonhosted.org/packages/99/5d/dab4339177a905aad3e2221c915b35202f1ec30d750dd2e5e9d9a72b804b/numpy-2.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4bbc7f303d125971f60ec0aaad5e12c62d0d2c925f0ab1273debd0e4ba37aba5", size = 14822302, upload-time = "2026-03-29T13:19:57.585Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e4/0564a65e7d3d97562ed6f9b0fd0fb0a6f559ee444092f105938b50043876/numpy-2.4.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:4d6d57903571f86180eb98f8f0c839fa9ebbfb031356d87f1361be91e433f5b7", size = 5327407, upload-time = "2026-03-29T13:20:00.601Z" }, + { url = "https://files.pythonhosted.org/packages/29/8d/35a3a6ce5ad371afa58b4700f1c820f8f279948cca32524e0a695b0ded83/numpy-2.4.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:4636de7fd195197b7535f231b5de9e4b36d2c440b6e566d2e4e4746e6af0ca93", size = 6647631, upload-time = "2026-03-29T13:20:02.855Z" }, + { url = "https://files.pythonhosted.org/packages/f4/da/477731acbd5a58a946c736edfdabb2ac5b34c3d08d1ba1a7b437fa0884df/numpy-2.4.4-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ad2e2ef14e0b04e544ea2fa0a36463f847f113d314aa02e5b402fdf910ef309e", size = 15727691, upload-time = "2026-03-29T13:20:06.004Z" }, + { url = "https://files.pythonhosted.org/packages/e6/db/338535d9b152beabeb511579598418ba0212ce77cf9718edd70262cc4370/numpy-2.4.4-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a285b3b96f951841799528cd1f4f01cd70e7e0204b4abebac9463eecfcf2a40", size = 16681241, upload-time = "2026-03-29T13:20:09.417Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a9/ad248e8f58beb7a0219b413c9c7d8151c5d285f7f946c3e26695bdbbe2df/numpy-2.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f8474c4241bc18b750be2abea9d7a9ec84f46ef861dbacf86a4f6e043401f79e", size = 17085767, upload-time = "2026-03-29T13:20:13.126Z" }, + { url = "https://files.pythonhosted.org/packages/b5/1a/3b88ccd3694681356f70da841630e4725a7264d6a885c8d442a697e1146b/numpy-2.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4e874c976154687c1f71715b034739b45c7711bec81db01914770373d125e392", size = 18403169, upload-time = "2026-03-29T13:20:17.096Z" }, + { url = "https://files.pythonhosted.org/packages/c2/c9/fcfd5d0639222c6eac7f304829b04892ef51c96a75d479214d77e3ce6e33/numpy-2.4.4-cp313-cp313t-win32.whl", hash = "sha256:9c585a1790d5436a5374bac930dad6ed244c046ed91b2b2a3634eb2971d21008", size = 6083477, upload-time = "2026-03-29T13:20:20.195Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e3/3938a61d1c538aaec8ed6fd6323f57b0c2d2d2219512434c5c878db76553/numpy-2.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:93e15038125dc1e5345d9b5b68aa7f996ec33b98118d18c6ca0d0b7d6198b7e8", size = 12457487, upload-time = "2026-03-29T13:20:22.946Z" }, + { url = "https://files.pythonhosted.org/packages/97/6a/7e345032cc60501721ef94e0e30b60f6b0bd601f9174ebd36389a2b86d40/numpy-2.4.4-cp313-cp313t-win_arm64.whl", hash = "sha256:0dfd3f9d3adbe2920b68b5cd3d51444e13a10792ec7154cd0a2f6e74d4ab3233", size = 10292002, upload-time = "2026-03-29T13:20:25.909Z" }, + { url = "https://files.pythonhosted.org/packages/6e/06/c54062f85f673dd5c04cbe2f14c3acb8c8b95e3384869bb8cc9bff8cb9df/numpy-2.4.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f169b9a863d34f5d11b8698ead99febeaa17a13ca044961aa8e2662a6c7766a0", size = 16684353, upload-time = "2026-03-29T13:20:29.504Z" }, + { url = "https://files.pythonhosted.org/packages/4c/39/8a320264a84404c74cc7e79715de85d6130fa07a0898f67fb5cd5bd79908/numpy-2.4.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2483e4584a1cb3092da4470b38866634bafb223cbcd551ee047633fd2584599a", size = 14704914, upload-time = "2026-03-29T13:20:33.547Z" }, + { url = "https://files.pythonhosted.org/packages/91/fb/287076b2614e1d1044235f50f03748f31fa287e3dbe6abeb35cdfa351eca/numpy-2.4.4-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:2d19e6e2095506d1736b7d80595e0f252d76b89f5e715c35e06e937679ea7d7a", size = 5210005, upload-time = "2026-03-29T13:20:36.45Z" }, + { url = "https://files.pythonhosted.org/packages/63/eb/fcc338595309910de6ecabfcef2419a9ce24399680bfb149421fa2df1280/numpy-2.4.4-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:6a246d5914aa1c820c9443ddcee9c02bec3e203b0c080349533fae17727dfd1b", size = 6544974, upload-time = "2026-03-29T13:20:39.014Z" }, + { url = "https://files.pythonhosted.org/packages/44/5d/e7e9044032a716cdfaa3fba27a8e874bf1c5f1912a1ddd4ed071bf8a14a6/numpy-2.4.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:989824e9faf85f96ec9c7761cd8d29c531ad857bfa1daa930cba85baaecf1a9a", size = 15684591, upload-time = "2026-03-29T13:20:42.146Z" }, + { url = "https://files.pythonhosted.org/packages/98/7c/21252050676612625449b4807d6b695b9ce8a7c9e1c197ee6216c8a65c7c/numpy-2.4.4-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:27a8d92cd10f1382a67d7cf4db7ce18341b66438bdd9f691d7b0e48d104c2a9d", size = 16637700, upload-time = "2026-03-29T13:20:46.204Z" }, + { url = "https://files.pythonhosted.org/packages/b1/29/56d2bbef9465db24ef25393383d761a1af4f446a1df9b8cded4fe3a5a5d7/numpy-2.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e44319a2953c738205bf3354537979eaa3998ed673395b964c1176083dd46252", size = 17035781, upload-time = "2026-03-29T13:20:50.242Z" }, + { url = "https://files.pythonhosted.org/packages/e3/2b/a35a6d7589d21f44cea7d0a98de5ddcbb3d421b2622a5c96b1edf18707c3/numpy-2.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e892aff75639bbef0d2a2cfd55535510df26ff92f63c92cd84ef8d4ba5a5557f", size = 18362959, upload-time = "2026-03-29T13:20:54.019Z" }, + { url = "https://files.pythonhosted.org/packages/64/c9/d52ec581f2390e0f5f85cbfd80fb83d965fc15e9f0e1aec2195faa142cde/numpy-2.4.4-cp314-cp314-win32.whl", hash = "sha256:1378871da56ca8943c2ba674530924bb8ca40cd228358a3b5f302ad60cf875fc", size = 6008768, upload-time = "2026-03-29T13:20:56.912Z" }, + { url = "https://files.pythonhosted.org/packages/fa/22/4cc31a62a6c7b74a8730e31a4274c5dc80e005751e277a2ce38e675e4923/numpy-2.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:715d1c092715954784bc79e1174fc2a90093dc4dc84ea15eb14dad8abdcdeb74", size = 12449181, upload-time = "2026-03-29T13:20:59.548Z" }, + { url = "https://files.pythonhosted.org/packages/70/2e/14cda6f4d8e396c612d1bf97f22958e92148801d7e4f110cabebdc0eef4b/numpy-2.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:2c194dd721e54ecad9ad387c1d35e63dce5c4450c6dc7dd5611283dda239aabb", size = 10496035, upload-time = "2026-03-29T13:21:02.524Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e8/8fed8c8d848d7ecea092dc3469643f9d10bc3a134a815a3b033da1d2039b/numpy-2.4.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2aa0613a5177c264ff5921051a5719d20095ea586ca88cc802c5c218d1c67d3e", size = 14824958, upload-time = "2026-03-29T13:21:05.671Z" }, + { url = "https://files.pythonhosted.org/packages/05/1a/d8007a5138c179c2bf33ef44503e83d70434d2642877ee8fbb230e7c0548/numpy-2.4.4-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:42c16925aa5a02362f986765f9ebabf20de75cdefdca827d14315c568dcab113", size = 5330020, upload-time = "2026-03-29T13:21:08.635Z" }, + { url = "https://files.pythonhosted.org/packages/99/64/ffb99ac6ae93faf117bcbd5c7ba48a7f45364a33e8e458545d3633615dda/numpy-2.4.4-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:874f200b2a981c647340f841730fc3a2b54c9d940566a3c4149099591e2c4c3d", size = 6650758, upload-time = "2026-03-29T13:21:10.949Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6e/795cc078b78a384052e73b2f6281ff7a700e9bf53bcce2ee579d4f6dd879/numpy-2.4.4-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c9b39d38a9bd2ae1becd7eac1303d031c5c110ad31f2b319c6e7d98b135c934d", size = 15729948, upload-time = "2026-03-29T13:21:14.047Z" }, + { url = "https://files.pythonhosted.org/packages/5f/86/2acbda8cc2af5f3d7bfc791192863b9e3e19674da7b5e533fded124d1299/numpy-2.4.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b268594bccac7d7cf5844c7732e3f20c50921d94e36d7ec9b79e9857694b1b2f", size = 16679325, upload-time = "2026-03-29T13:21:17.561Z" }, + { url = "https://files.pythonhosted.org/packages/bc/59/cafd83018f4aa55e0ac6fa92aa066c0a1877b77a615ceff1711c260ffae8/numpy-2.4.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ac6b31e35612a26483e20750126d30d0941f949426974cace8e6b5c58a3657b0", size = 17084883, upload-time = "2026-03-29T13:21:21.106Z" }, + { url = "https://files.pythonhosted.org/packages/f0/85/a42548db84e65ece46ab2caea3d3f78b416a47af387fcbb47ec28e660dc2/numpy-2.4.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:8e3ed142f2728df44263aaf5fb1f5b0b99f4070c553a0d7f033be65338329150", size = 18403474, upload-time = "2026-03-29T13:21:24.828Z" }, + { url = "https://files.pythonhosted.org/packages/ed/ad/483d9e262f4b831000062e5d8a45e342166ec8aaa1195264982bca267e62/numpy-2.4.4-cp314-cp314t-win32.whl", hash = "sha256:dddbbd259598d7240b18c9d87c56a9d2fb3b02fe266f49a7c101532e78c1d871", size = 6155500, upload-time = "2026-03-29T13:21:28.205Z" }, + { url = "https://files.pythonhosted.org/packages/c7/03/2fc4e14c7bd4ff2964b74ba90ecb8552540b6315f201df70f137faa5c589/numpy-2.4.4-cp314-cp314t-win_amd64.whl", hash = "sha256:a7164afb23be6e37ad90b2f10426149fd75aee07ca55653d2aa41e66c4ef697e", size = 12637755, upload-time = "2026-03-29T13:21:31.107Z" }, + { url = "https://files.pythonhosted.org/packages/58/78/548fb8e07b1a341746bfbecb32f2c268470f45fa028aacdbd10d9bc73aab/numpy-2.4.4-cp314-cp314t-win_arm64.whl", hash = "sha256:ba203255017337d39f89bdd58417f03c4426f12beed0440cfd933cb15f8669c7", size = 10566643, upload-time = "2026-03-29T13:21:34.339Z" }, ] [[package]] @@ -1387,24 +1681,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/63/7c/5c2892e6bc0628a2ccf4e938e1e2db22794657ccb374672d66e20d73839e/numpy_typing_compat-20251206.2.4-py3-none-any.whl", hash = "sha256:a82e723bd20efaa4cf2886709d4264c144f1f2b609bda83d1545113b7e47a5b5", size = 6300, upload-time = "2025-12-06T20:01:57.578Z" }, ] -[[package]] -name = "opencv-python" -version = "4.13.0.92" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/6f/5a28fef4c4a382be06afe3938c64cc168223016fa520c5abaf37e8862aa5/opencv_python-4.13.0.92-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:caf60c071ec391ba51ed00a4a920f996d0b64e3e46068aac1f646b5de0326a19", size = 46247052, upload-time = "2026-02-05T07:01:25.046Z" }, - { url = "https://files.pythonhosted.org/packages/08/ac/6c98c44c650b8114a0fb901691351cfb3956d502e8e9b5cd27f4ee7fbf2f/opencv_python-4.13.0.92-cp37-abi3-macosx_14_0_x86_64.whl", hash = "sha256:5868a8c028a0b37561579bfb8ac1875babdc69546d236249fff296a8c010ccf9", size = 32568781, upload-time = "2026-02-05T07:01:41.379Z" }, - { url = "https://files.pythonhosted.org/packages/3e/51/82fed528b45173bf629fa44effb76dff8bc9f4eeaee759038362dfa60237/opencv_python-4.13.0.92-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0bc2596e68f972ca452d80f444bc404e08807d021fbba40df26b61b18e01838a", size = 47685527, upload-time = "2026-02-05T06:59:11.24Z" }, - { url = "https://files.pythonhosted.org/packages/db/07/90b34a8e2cf9c50fe8ed25cac9011cde0676b4d9d9c973751ac7616223a2/opencv_python-4.13.0.92-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:402033cddf9d294693094de5ef532339f14ce821da3ad7df7c9f6e8316da32cf", size = 70460872, upload-time = "2026-02-05T06:59:19.162Z" }, - { url = "https://files.pythonhosted.org/packages/02/6d/7a9cc719b3eaf4377b9c2e3edeb7ed3a81de41f96421510c0a169ca3cfd4/opencv_python-4.13.0.92-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:bccaabf9eb7f897ca61880ce2869dcd9b25b72129c28478e7f2a5e8dee945616", size = 46708208, upload-time = "2026-02-05T06:59:15.419Z" }, - { url = "https://files.pythonhosted.org/packages/fd/55/b3b49a1b97aabcfbbd6c7326df9cb0b6fa0c0aefa8e89d500939e04aa229/opencv_python-4.13.0.92-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:620d602b8f7d8b8dab5f4b99c6eb353e78d3fb8b0f53db1bd258bb1aa001c1d5", size = 72927042, upload-time = "2026-02-05T06:59:23.389Z" }, - { url = "https://files.pythonhosted.org/packages/fb/17/de5458312bcb07ddf434d7bfcb24bb52c59635ad58c6e7c751b48949b009/opencv_python-4.13.0.92-cp37-abi3-win32.whl", hash = "sha256:372fe164a3148ac1ca51e5f3ad0541a4a276452273f503441d718fab9c5e5f59", size = 30932638, upload-time = "2026-02-05T07:02:14.98Z" }, - { url = "https://files.pythonhosted.org/packages/e9/a5/1be1516390333ff9be3a9cb648c9f33df79d5096e5884b5df71a588af463/opencv_python-4.13.0.92-cp37-abi3-win_amd64.whl", hash = "sha256:423d934c9fafb91aad38edf26efb46da91ffbc05f3f59c4b0c72e699720706f5", size = 40212062, upload-time = "2026-02-05T07:02:12.724Z" }, -] - [[package]] name = "openpyxl" version = "3.1.5" @@ -1446,54 +1722,54 @@ wheels = [ [[package]] name = "pandas" -version = "3.0.1" +version = "3.0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/0c/b28ed414f080ee0ad153f848586d61d1878f91689950f037f976ce15f6c8/pandas-3.0.1.tar.gz", hash = "sha256:4186a699674af418f655dbd420ed87f50d56b4cd6603784279d9eef6627823c8", size = 4641901, upload-time = "2026-02-17T22:20:16.434Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/37/51/b467209c08dae2c624873d7491ea47d2b47336e5403309d433ea79c38571/pandas-3.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:476f84f8c20c9f5bc47252b66b4bb25e1a9fc2fa98cead96744d8116cb85771d", size = 10344357, upload-time = "2026-02-17T22:18:38.262Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f1/e2567ffc8951ab371db2e40b2fe068e36b81d8cf3260f06ae508700e5504/pandas-3.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0ab749dfba921edf641d4036c4c21c0b3ea70fea478165cb98a998fb2a261955", size = 9884543, upload-time = "2026-02-17T22:18:41.476Z" }, - { url = "https://files.pythonhosted.org/packages/d7/39/327802e0b6d693182403c144edacbc27eb82907b57062f23ef5a4c4a5ea7/pandas-3.0.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8e36891080b87823aff3640c78649b91b8ff6eea3c0d70aeabd72ea43ab069b", size = 10396030, upload-time = "2026-02-17T22:18:43.822Z" }, - { url = "https://files.pythonhosted.org/packages/3d/fe/89d77e424365280b79d99b3e1e7d606f5165af2f2ecfaf0c6d24c799d607/pandas-3.0.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:532527a701281b9dd371e2f582ed9094f4c12dd9ffb82c0c54ee28d8ac9520c4", size = 10876435, upload-time = "2026-02-17T22:18:45.954Z" }, - { url = "https://files.pythonhosted.org/packages/b5/a6/2a75320849dd154a793f69c951db759aedb8d1dd3939eeacda9bdcfa1629/pandas-3.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:356e5c055ed9b0da1580d465657bc7d00635af4fd47f30afb23025352ba764d1", size = 11405133, upload-time = "2026-02-17T22:18:48.533Z" }, - { url = "https://files.pythonhosted.org/packages/58/53/1d68fafb2e02d7881df66aa53be4cd748d25cbe311f3b3c85c93ea5d30ca/pandas-3.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9d810036895f9ad6345b8f2a338dd6998a74e8483847403582cab67745bff821", size = 11932065, upload-time = "2026-02-17T22:18:50.837Z" }, - { url = "https://files.pythonhosted.org/packages/75/08/67cc404b3a966b6df27b38370ddd96b3b023030b572283d035181854aac5/pandas-3.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:536232a5fe26dd989bd633e7a0c450705fdc86a207fec7254a55e9a22950fe43", size = 9741627, upload-time = "2026-02-17T22:18:53.905Z" }, - { url = "https://files.pythonhosted.org/packages/86/4f/caf9952948fb00d23795f09b893d11f1cacb384e666854d87249530f7cbe/pandas-3.0.1-cp312-cp312-win_arm64.whl", hash = "sha256:0f463ebfd8de7f326d38037c7363c6dacb857c5881ab8961fb387804d6daf2f7", size = 9052483, upload-time = "2026-02-17T22:18:57.31Z" }, - { url = "https://files.pythonhosted.org/packages/0b/48/aad6ec4f8d007534c091e9a7172b3ec1b1ee6d99a9cbb936b5eab6c6cf58/pandas-3.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5272627187b5d9c20e55d27caf5f2cd23e286aba25cadf73c8590e432e2b7262", size = 10317509, upload-time = "2026-02-17T22:18:59.498Z" }, - { url = "https://files.pythonhosted.org/packages/a8/14/5990826f779f79148ae9d3a2c39593dc04d61d5d90541e71b5749f35af95/pandas-3.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:661e0f665932af88c7877f31da0dc743fe9c8f2524bdffe23d24fdcb67ef9d56", size = 9860561, upload-time = "2026-02-17T22:19:02.265Z" }, - { url = "https://files.pythonhosted.org/packages/fa/80/f01ff54664b6d70fed71475543d108a9b7c888e923ad210795bef04ffb7d/pandas-3.0.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:75e6e292ff898679e47a2199172593d9f6107fd2dd3617c22c2946e97d5df46e", size = 10365506, upload-time = "2026-02-17T22:19:05.017Z" }, - { url = "https://files.pythonhosted.org/packages/f2/85/ab6d04733a7d6ff32bfc8382bf1b07078228f5d6ebec5266b91bfc5c4ff7/pandas-3.0.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1ff8cf1d2896e34343197685f432450ec99a85ba8d90cce2030c5eee2ef98791", size = 10873196, upload-time = "2026-02-17T22:19:07.204Z" }, - { url = "https://files.pythonhosted.org/packages/48/a9/9301c83d0b47c23ac5deab91c6b39fd98d5b5db4d93b25df8d381451828f/pandas-3.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eca8b4510f6763f3d37359c2105df03a7a221a508f30e396a51d0713d462e68a", size = 11370859, upload-time = "2026-02-17T22:19:09.436Z" }, - { url = "https://files.pythonhosted.org/packages/59/fe/0c1fc5bd2d29c7db2ab372330063ad555fb83e08422829c785f5ec2176ca/pandas-3.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:06aff2ad6f0b94a17822cf8b83bbb563b090ed82ff4fe7712db2ce57cd50d9b8", size = 11924584, upload-time = "2026-02-17T22:19:11.562Z" }, - { url = "https://files.pythonhosted.org/packages/d6/7d/216a1588b65a7aa5f4535570418a599d943c85afb1d95b0876fc00aa1468/pandas-3.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:9fea306c783e28884c29057a1d9baa11a349bbf99538ec1da44c8476563d1b25", size = 9742769, upload-time = "2026-02-17T22:19:13.926Z" }, - { url = "https://files.pythonhosted.org/packages/c4/cb/810a22a6af9a4e97c8ab1c946b47f3489c5bca5adc483ce0ffc84c9cc768/pandas-3.0.1-cp313-cp313-win_arm64.whl", hash = "sha256:a8d37a43c52917427e897cb2e429f67a449327394396a81034a4449b99afda59", size = 9043855, upload-time = "2026-02-17T22:19:16.09Z" }, - { url = "https://files.pythonhosted.org/packages/92/fa/423c89086cca1f039cf1253c3ff5b90f157b5b3757314aa635f6bf3e30aa/pandas-3.0.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d54855f04f8246ed7b6fc96b05d4871591143c46c0b6f4af874764ed0d2d6f06", size = 10752673, upload-time = "2026-02-17T22:19:18.304Z" }, - { url = "https://files.pythonhosted.org/packages/22/23/b5a08ec1f40020397f0faba72f1e2c11f7596a6169c7b3e800abff0e433f/pandas-3.0.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e1b677accee34a09e0dc2ce5624e4a58a1870ffe56fc021e9caf7f23cd7668f", size = 10404967, upload-time = "2026-02-17T22:19:20.726Z" }, - { url = "https://files.pythonhosted.org/packages/5c/81/94841f1bb4afdc2b52a99daa895ac2c61600bb72e26525ecc9543d453ebc/pandas-3.0.1-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a9cabbdcd03f1b6cd254d6dda8ae09b0252524be1592594c00b7895916cb1324", size = 10320575, upload-time = "2026-02-17T22:19:24.919Z" }, - { url = "https://files.pythonhosted.org/packages/0a/8b/2ae37d66a5342a83adadfd0cb0b4bf9c3c7925424dd5f40d15d6cfaa35ee/pandas-3.0.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ae2ab1f166668b41e770650101e7090824fd34d17915dd9cd479f5c5e0065e9", size = 10710921, upload-time = "2026-02-17T22:19:27.181Z" }, - { url = "https://files.pythonhosted.org/packages/a2/61/772b2e2757855e232b7ccf7cb8079a5711becb3a97f291c953def15a833f/pandas-3.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6bf0603c2e30e2cafac32807b06435f28741135cb8697eae8b28c7d492fc7d76", size = 11334191, upload-time = "2026-02-17T22:19:29.411Z" }, - { url = "https://files.pythonhosted.org/packages/1b/08/b16c6df3ef555d8495d1d265a7963b65be166785d28f06a350913a4fac78/pandas-3.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c426422973973cae1f4a23e51d4ae85974f44871b24844e4f7de752dd877098", size = 11782256, upload-time = "2026-02-17T22:19:32.34Z" }, - { url = "https://files.pythonhosted.org/packages/55/80/178af0594890dee17e239fca96d3d8670ba0f5ff59b7d0439850924a9c09/pandas-3.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b03f91ae8c10a85c1613102c7bef5229b5379f343030a3ccefeca8a33414cf35", size = 10485047, upload-time = "2026-02-17T22:19:34.605Z" }, - { url = "https://files.pythonhosted.org/packages/bb/8b/4bb774a998b97e6c2fd62a9e6cfdaae133b636fd1c468f92afb4ae9a447a/pandas-3.0.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:99d0f92ed92d3083d140bf6b97774f9f13863924cf3f52a70711f4e7588f9d0a", size = 10322465, upload-time = "2026-02-17T22:19:36.803Z" }, - { url = "https://files.pythonhosted.org/packages/72/3a/5b39b51c64159f470f1ca3b1c2a87da290657ca022f7cd11442606f607d1/pandas-3.0.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3b66857e983208654294bb6477b8a63dee26b37bdd0eb34d010556e91261784f", size = 9910632, upload-time = "2026-02-17T22:19:39.001Z" }, - { url = "https://files.pythonhosted.org/packages/4e/f7/b449ffb3f68c11da12fc06fbf6d2fa3a41c41e17d0284d23a79e1c13a7e4/pandas-3.0.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56cf59638bf24dc9bdf2154c81e248b3289f9a09a6d04e63608c159022352749", size = 10440535, upload-time = "2026-02-17T22:19:41.157Z" }, - { url = "https://files.pythonhosted.org/packages/55/77/6ea82043db22cb0f2bbfe7198da3544000ddaadb12d26be36e19b03a2dc5/pandas-3.0.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1a9f55e0f46951874b863d1f3906dcb57df2d9be5c5847ba4dfb55b2c815249", size = 10893940, upload-time = "2026-02-17T22:19:43.493Z" }, - { url = "https://files.pythonhosted.org/packages/03/30/f1b502a72468c89412c1b882a08f6eed8a4ee9dc033f35f65d0663df6081/pandas-3.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1849f0bba9c8a2fb0f691d492b834cc8dadf617e29015c66e989448d58d011ee", size = 11442711, upload-time = "2026-02-17T22:19:46.074Z" }, - { url = "https://files.pythonhosted.org/packages/0d/f0/ebb6ddd8fc049e98cabac5c2924d14d1dda26a20adb70d41ea2e428d3ec4/pandas-3.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3d288439e11b5325b02ae6e9cc83e6805a62c40c5a6220bea9beb899c073b1c", size = 11963918, upload-time = "2026-02-17T22:19:48.838Z" }, - { url = "https://files.pythonhosted.org/packages/09/f8/8ce132104074f977f907442790eaae24e27bce3b3b454e82faa3237ff098/pandas-3.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:93325b0fe372d192965f4cca88d97667f49557398bbf94abdda3bf1b591dbe66", size = 9862099, upload-time = "2026-02-17T22:19:51.081Z" }, - { url = "https://files.pythonhosted.org/packages/e6/b7/6af9aac41ef2456b768ef0ae60acf8abcebb450a52043d030a65b4b7c9bd/pandas-3.0.1-cp314-cp314-win_arm64.whl", hash = "sha256:97ca08674e3287c7148f4858b01136f8bdfe7202ad25ad04fec602dd1d29d132", size = 9185333, upload-time = "2026-02-17T22:19:53.266Z" }, - { url = "https://files.pythonhosted.org/packages/66/fc/848bb6710bc6061cb0c5badd65b92ff75c81302e0e31e496d00029fe4953/pandas-3.0.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:58eeb1b2e0fb322befcf2bbc9ba0af41e616abadb3d3414a6bc7167f6cbfce32", size = 10772664, upload-time = "2026-02-17T22:19:55.806Z" }, - { url = "https://files.pythonhosted.org/packages/69/5c/866a9bbd0f79263b4b0db6ec1a341be13a1473323f05c122388e0f15b21d/pandas-3.0.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cd9af1276b5ca9e298bd79a26bda32fa9cc87ed095b2a9a60978d2ca058eaf87", size = 10421286, upload-time = "2026-02-17T22:19:58.091Z" }, - { url = "https://files.pythonhosted.org/packages/51/a4/2058fb84fb1cfbfb2d4a6d485e1940bb4ad5716e539d779852494479c580/pandas-3.0.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94f87a04984d6b63788327cd9f79dda62b7f9043909d2440ceccf709249ca988", size = 10342050, upload-time = "2026-02-17T22:20:01.376Z" }, - { url = "https://files.pythonhosted.org/packages/22/1b/674e89996cc4be74db3c4eb09240c4bb549865c9c3f5d9b086ff8fcfbf00/pandas-3.0.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85fe4c4df62e1e20f9db6ebfb88c844b092c22cd5324bdcf94bfa2fc1b391221", size = 10740055, upload-time = "2026-02-17T22:20:04.328Z" }, - { url = "https://files.pythonhosted.org/packages/d0/f8/e954b750764298c22fa4614376531fe63c521ef517e7059a51f062b87dca/pandas-3.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:331ca75a2f8672c365ae25c0b29e46f5ac0c6551fdace8eec4cd65e4fac271ff", size = 11357632, upload-time = "2026-02-17T22:20:06.647Z" }, - { url = "https://files.pythonhosted.org/packages/6d/02/c6e04b694ffd68568297abd03588b6d30295265176a5c01b7459d3bc35a3/pandas-3.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:15860b1fdb1973fffade772fdb931ccf9b2f400a3f5665aef94a00445d7d8dd5", size = 11810974, upload-time = "2026-02-17T22:20:08.946Z" }, - { url = "https://files.pythonhosted.org/packages/89/41/d7dfb63d2407f12055215070c42fc6ac41b66e90a2946cdc5e759058398b/pandas-3.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:44f1364411d5670efa692b146c748f4ed013df91ee91e9bec5677fb1fd58b937", size = 10884622, upload-time = "2026-02-17T22:20:11.711Z" }, - { url = "https://files.pythonhosted.org/packages/68/b0/34937815889fa982613775e4b97fddd13250f11012d769949c5465af2150/pandas-3.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:108dd1790337a494aa80e38def654ca3f0968cf4f362c85f44c15e471667102d", size = 9452085, upload-time = "2026-02-17T22:20:14.331Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/da/99/b342345300f13440fe9fe385c3c481e2d9a595ee3bab4d3219247ac94e9a/pandas-3.0.2.tar.gz", hash = "sha256:f4753e73e34c8d83221ba58f232433fca2748be8b18dbca02d242ed153945043", size = 4645855, upload-time = "2026-03-31T06:48:30.816Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/b0/c20bd4d6d3f736e6bd6b55794e9cd0a617b858eaad27c8f410ea05d953b7/pandas-3.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:232a70ebb568c0c4d2db4584f338c1577d81e3af63292208d615907b698a0f18", size = 10347921, upload-time = "2026-03-31T06:46:33.36Z" }, + { url = "https://files.pythonhosted.org/packages/35/d0/4831af68ce30cc2d03c697bea8450e3225a835ef497d0d70f31b8cdde965/pandas-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:970762605cff1ca0d3f71ed4f3a769ea8f85fc8e6348f6e110b8fea7e6eb5a14", size = 9888127, upload-time = "2026-03-31T06:46:36.253Z" }, + { url = "https://files.pythonhosted.org/packages/61/a9/16ea9346e1fc4a96e2896242d9bc674764fb9049b0044c0132502f7a771e/pandas-3.0.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aff4e6f4d722e0652707d7bcb190c445fe58428500c6d16005b02401764b1b3d", size = 10399577, upload-time = "2026-03-31T06:46:39.224Z" }, + { url = "https://files.pythonhosted.org/packages/c4/a8/3a61a721472959ab0ce865ef05d10b0d6bfe27ce8801c99f33d4fa996e65/pandas-3.0.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef8b27695c3d3dc78403c9a7d5e59a62d5464a7e1123b4e0042763f7104dc74f", size = 10880030, upload-time = "2026-03-31T06:46:42.412Z" }, + { url = "https://files.pythonhosted.org/packages/da/65/7225c0ea4d6ce9cb2160a7fb7f39804871049f016e74782e5dade4d14109/pandas-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f8d68083e49e16b84734eb1a4dcae4259a75c90fb6e2251ab9a00b61120c06ab", size = 11409468, upload-time = "2026-03-31T06:46:45.2Z" }, + { url = "https://files.pythonhosted.org/packages/fa/5b/46e7c76032639f2132359b5cf4c785dd8cf9aea5ea64699eac752f02b9db/pandas-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:32cc41f310ebd4a296d93515fcac312216adfedb1894e879303987b8f1e2b97d", size = 11936381, upload-time = "2026-03-31T06:46:48.293Z" }, + { url = "https://files.pythonhosted.org/packages/7b/8b/721a9cff6fa6a91b162eb51019c6243b82b3226c71bb6c8ef4a9bd65cbc6/pandas-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:a4785e1d6547d8427c5208b748ae2efb64659a21bd82bf440d4262d02bfa02a4", size = 9744993, upload-time = "2026-03-31T06:46:51.488Z" }, + { url = "https://files.pythonhosted.org/packages/d5/18/7f0bd34ae27b28159aa80f2a6799f47fda34f7fb938a76e20c7b7fe3b200/pandas-3.0.2-cp312-cp312-win_arm64.whl", hash = "sha256:08504503f7101300107ecdc8df73658e4347586db5cfdadabc1592e9d7e7a0fd", size = 9056118, upload-time = "2026-03-31T06:46:54.548Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ca/3e639a1ea6fcd0617ca4e8ca45f62a74de33a56ae6cd552735470b22c8d3/pandas-3.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b5918ba197c951dec132b0c5929a00c0bf05d5942f590d3c10a807f6e15a57d3", size = 10321105, upload-time = "2026-03-31T06:46:57.327Z" }, + { url = "https://files.pythonhosted.org/packages/0b/77/dbc82ff2fb0e63c6564356682bf201edff0ba16c98630d21a1fb312a8182/pandas-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d606a041c89c0a474a4702d532ab7e73a14fe35c8d427b972a625c8e46373668", size = 9864088, upload-time = "2026-03-31T06:46:59.935Z" }, + { url = "https://files.pythonhosted.org/packages/5c/2b/341f1b04bbca2e17e13cd3f08c215b70ef2c60c5356ef1e8c6857449edc7/pandas-3.0.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:710246ba0616e86891b58ab95f2495143bb2bc83ab6b06747c74216f583a6ac9", size = 10369066, upload-time = "2026-03-31T06:47:02.792Z" }, + { url = "https://files.pythonhosted.org/packages/12/c5/cbb1ffefb20a93d3f0e1fdcda699fb84976210d411b008f97f48bf6ce27e/pandas-3.0.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5d3cfe227c725b1f3dff4278b43d8c784656a42a9325b63af6b1492a8232209e", size = 10876780, upload-time = "2026-03-31T06:47:06.205Z" }, + { url = "https://files.pythonhosted.org/packages/98/fe/2249ae5e0a69bd0ddf17353d0a5d26611d70970111f5b3600cdc8be883e7/pandas-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c3b723df9087a9a9a840e263ebd9f88b64a12075d1bf2ea401a5a42f254f084d", size = 11375181, upload-time = "2026-03-31T06:47:09.383Z" }, + { url = "https://files.pythonhosted.org/packages/de/64/77a38b09e70b6464883b8d7584ab543e748e42c1b5d337a2ee088e0df741/pandas-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a3096110bf9eac0070b7208465f2740e2d8a670d5cb6530b5bb884eca495fd39", size = 11928899, upload-time = "2026-03-31T06:47:12.686Z" }, + { url = "https://files.pythonhosted.org/packages/5e/52/42855bf626868413f761addd574acc6195880ae247a5346477a4361c3acb/pandas-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:07a10f5c36512eead51bc578eb3354ad17578b22c013d89a796ab5eee90cd991", size = 9746574, upload-time = "2026-03-31T06:47:15.64Z" }, + { url = "https://files.pythonhosted.org/packages/88/39/21304ae06a25e8bf9fc820d69b29b2c495b2ae580d1e143146c309941760/pandas-3.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:5fdbfa05931071aba28b408e59226186b01eb5e92bea2ab78b65863ca3228d84", size = 9047156, upload-time = "2026-03-31T06:47:18.595Z" }, + { url = "https://files.pythonhosted.org/packages/72/20/7defa8b27d4f330a903bb68eea33be07d839c5ea6bdda54174efcec0e1d2/pandas-3.0.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:dbc20dea3b9e27d0e66d74c42b2d0c1bed9c2ffe92adea33633e3bedeb5ac235", size = 10756238, upload-time = "2026-03-31T06:47:22.012Z" }, + { url = "https://files.pythonhosted.org/packages/e9/95/49433c14862c636afc0e9b2db83ff16b3ad92959364e52b2955e44c8e94c/pandas-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b75c347eff42497452116ce05ef461822d97ce5b9ff8df6edacb8076092c855d", size = 10408520, upload-time = "2026-03-31T06:47:25.197Z" }, + { url = "https://files.pythonhosted.org/packages/3b/f8/462ad2b5881d6b8ec8e5f7ed2ea1893faa02290d13870a1600fe72ad8efc/pandas-3.0.2-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d1478075142e83a5571782ad007fb201ed074bdeac7ebcc8890c71442e96adf7", size = 10324154, upload-time = "2026-03-31T06:47:28.097Z" }, + { url = "https://files.pythonhosted.org/packages/0a/65/d1e69b649cbcddda23ad6e4c40ef935340f6f652a006e5cbc3555ac8adb3/pandas-3.0.2-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5880314e69e763d4c8b27937090de570f1fb8d027059a7ada3f7f8e98bdcb677", size = 10714449, upload-time = "2026-03-31T06:47:30.85Z" }, + { url = "https://files.pythonhosted.org/packages/47/a4/85b59bc65b8190ea3689882db6cdf32a5003c0ccd5a586c30fdcc3ffc4fc/pandas-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b5329e26898896f06035241a626d7c335daa479b9bbc82be7c2742d048e41172", size = 11338475, upload-time = "2026-03-31T06:47:34.026Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c4/bc6966c6e38e5d9478b935272d124d80a589511ed1612a5d21d36f664c68/pandas-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:81526c4afd31971f8b62671442a4b2b51e0aa9acc3819c9f0f12a28b6fcf85f1", size = 11786568, upload-time = "2026-03-31T06:47:36.941Z" }, + { url = "https://files.pythonhosted.org/packages/e8/74/09298ca9740beed1d3504e073d67e128aa07e5ca5ca2824b0c674c0b8676/pandas-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:7cadd7e9a44ec13b621aec60f9150e744cfc7a3dd32924a7e2f45edff31823b0", size = 10488652, upload-time = "2026-03-31T06:47:40.612Z" }, + { url = "https://files.pythonhosted.org/packages/bb/40/c6ea527147c73b24fc15c891c3fcffe9c019793119c5742b8784a062c7db/pandas-3.0.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:db0dbfd2a6cdf3770aa60464d50333d8f3d9165b2f2671bcc299b72de5a6677b", size = 10326084, upload-time = "2026-03-31T06:47:43.834Z" }, + { url = "https://files.pythonhosted.org/packages/95/25/bdb9326c3b5455f8d4d3549fce7abcf967259de146fe2cf7a82368141948/pandas-3.0.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0555c5882688a39317179ab4a0ed41d3ebc8812ab14c69364bbee8fb7a3f6288", size = 9914146, upload-time = "2026-03-31T06:47:46.67Z" }, + { url = "https://files.pythonhosted.org/packages/8d/77/3a227ff3337aa376c60d288e1d61c5d097131d0ac71f954d90a8f369e422/pandas-3.0.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:01f31a546acd5574ef77fe199bc90b55527c225c20ccda6601cf6b0fd5ed597c", size = 10444081, upload-time = "2026-03-31T06:47:49.681Z" }, + { url = "https://files.pythonhosted.org/packages/15/88/3cdd54fa279341afa10acf8d2b503556b1375245dccc9315659f795dd2e9/pandas-3.0.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:deeca1b5a931fdf0c2212c8a659ade6d3b1edc21f0914ce71ef24456ca7a6535", size = 10897535, upload-time = "2026-03-31T06:47:53.033Z" }, + { url = "https://files.pythonhosted.org/packages/06/9d/98cc7a7624f7932e40f434299260e2917b090a579d75937cb8a57b9d2de3/pandas-3.0.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0f48afd9bb13300ffb5a3316973324c787054ba6665cda0da3fbd67f451995db", size = 11446992, upload-time = "2026-03-31T06:47:56.193Z" }, + { url = "https://files.pythonhosted.org/packages/9a/cd/19ff605cc3760e80602e6826ddef2824d8e7050ed80f2e11c4b079741dc3/pandas-3.0.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6c4d8458b97a35717b62469a4ea0e85abd5ed8687277f5ccfc67f8a5126f8c53", size = 11968257, upload-time = "2026-03-31T06:47:59.137Z" }, + { url = "https://files.pythonhosted.org/packages/db/60/aba6a38de456e7341285102bede27514795c1eaa353bc0e7638b6b785356/pandas-3.0.2-cp314-cp314-win_amd64.whl", hash = "sha256:b35d14bb5d8285d9494fe93815a9e9307c0876e10f1e8e89ac5b88f728ec8dcf", size = 9865893, upload-time = "2026-03-31T06:48:02.038Z" }, + { url = "https://files.pythonhosted.org/packages/08/71/e5ec979dd2e8a093dacb8864598c0ff59a0cee0bbcdc0bfec16a51684d4f/pandas-3.0.2-cp314-cp314-win_arm64.whl", hash = "sha256:63d141b56ef686f7f0d714cfb8de4e320475b86bf4b620aa0b7da89af8cbdbbb", size = 9188644, upload-time = "2026-03-31T06:48:05.045Z" }, + { url = "https://files.pythonhosted.org/packages/f1/6c/7b45d85db19cae1eb524f2418ceaa9d85965dcf7b764ed151386b7c540f0/pandas-3.0.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:140f0cffb1fa2524e874dde5b477d9defe10780d8e9e220d259b2c0874c89d9d", size = 10776246, upload-time = "2026-03-31T06:48:07.789Z" }, + { url = "https://files.pythonhosted.org/packages/a8/3e/7b00648b086c106e81766f25322b48aa8dfa95b55e621dbdf2fdd413a117/pandas-3.0.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ae37e833ff4fed0ba352f6bdd8b73ba3ab3256a85e54edfd1ab51ae40cca0af8", size = 10424801, upload-time = "2026-03-31T06:48:10.897Z" }, + { url = "https://files.pythonhosted.org/packages/da/6e/558dd09a71b53b4008e7fc8a98ec6d447e9bfb63cdaeea10e5eb9b2dabe8/pandas-3.0.2-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d888a5c678a419a5bb41a2a93818e8ed9fd3172246555c0b37b7cc27027effd", size = 10345643, upload-time = "2026-03-31T06:48:13.7Z" }, + { url = "https://files.pythonhosted.org/packages/be/e3/921c93b4d9a280409451dc8d07b062b503bbec0531d2627e73a756e99a82/pandas-3.0.2-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b444dc64c079e84df91baa8bf613d58405645461cabca929d9178f2cd392398d", size = 10743641, upload-time = "2026-03-31T06:48:16.659Z" }, + { url = "https://files.pythonhosted.org/packages/56/ca/fd17286f24fa3b4d067965d8d5d7e14fe557dd4f979a0b068ac0deaf8228/pandas-3.0.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:4544c7a54920de8eeacaa1466a6b7268ecfbc9bc64ab4dbb89c6bbe94d5e0660", size = 11361993, upload-time = "2026-03-31T06:48:19.475Z" }, + { url = "https://files.pythonhosted.org/packages/e4/a5/2f6ed612056819de445a433ca1f2821ac3dab7f150d569a59e9cc105de1d/pandas-3.0.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:734be7551687c00fbd760dc0522ed974f82ad230d4a10f54bf51b80d44a08702", size = 11815274, upload-time = "2026-03-31T06:48:22.695Z" }, + { url = "https://files.pythonhosted.org/packages/00/2f/b622683e99ec3ce00b0854bac9e80868592c5b051733f2cf3a868e5fea26/pandas-3.0.2-cp314-cp314t-win_amd64.whl", hash = "sha256:57a07209bebcbcf768d2d13c9b78b852f9a15978dac41b9e6421a81ad4cdd276", size = 10888530, upload-time = "2026-03-31T06:48:25.806Z" }, + { url = "https://files.pythonhosted.org/packages/cb/2b/f8434233fab2bd66a02ec014febe4e5adced20e2693e0e90a07d118ed30e/pandas-3.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:5371b72c2d4d415d08765f32d689217a43227484e81b2305b52076e328f6f482", size = 9455341, upload-time = "2026-03-31T06:48:28.418Z" }, ] [[package]] @@ -1528,71 +1804,68 @@ wheels = [ [[package]] name = "pillow" -version = "12.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/d3/8df65da0d4df36b094351dce696f2989bec731d4f10e743b1c5f4da4d3bf/pillow-12.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052", size = 5262803, upload-time = "2026-02-11T04:20:47.653Z" }, - { url = "https://files.pythonhosted.org/packages/d6/71/5026395b290ff404b836e636f51d7297e6c83beceaa87c592718747e670f/pillow-12.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984", size = 4657601, upload-time = "2026-02-11T04:20:49.328Z" }, - { url = "https://files.pythonhosted.org/packages/b1/2e/1001613d941c67442f745aff0f7cc66dd8df9a9c084eb497e6a543ee6f7e/pillow-12.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79", size = 6234995, upload-time = "2026-02-11T04:20:51.032Z" }, - { url = "https://files.pythonhosted.org/packages/07/26/246ab11455b2549b9233dbd44d358d033a2f780fa9007b61a913c5b2d24e/pillow-12.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293", size = 8045012, upload-time = "2026-02-11T04:20:52.882Z" }, - { url = "https://files.pythonhosted.org/packages/b2/8b/07587069c27be7535ac1fe33874e32de118fbd34e2a73b7f83436a88368c/pillow-12.1.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397", size = 6349638, upload-time = "2026-02-11T04:20:54.444Z" }, - { url = "https://files.pythonhosted.org/packages/ff/79/6df7b2ee763d619cda2fb4fea498e5f79d984dae304d45a8999b80d6cf5c/pillow-12.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0", size = 7041540, upload-time = "2026-02-11T04:20:55.97Z" }, - { url = "https://files.pythonhosted.org/packages/2c/5e/2ba19e7e7236d7529f4d873bdaf317a318896bac289abebd4bb00ef247f0/pillow-12.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3", size = 6462613, upload-time = "2026-02-11T04:20:57.542Z" }, - { url = "https://files.pythonhosted.org/packages/03/03/31216ec124bb5c3dacd74ce8efff4cc7f52643653bad4825f8f08c697743/pillow-12.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35", size = 7166745, upload-time = "2026-02-11T04:20:59.196Z" }, - { url = "https://files.pythonhosted.org/packages/1f/e7/7c4552d80052337eb28653b617eafdef39adfb137c49dd7e831b8dc13bc5/pillow-12.1.1-cp312-cp312-win32.whl", hash = "sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a", size = 6328823, upload-time = "2026-02-11T04:21:01.385Z" }, - { url = "https://files.pythonhosted.org/packages/3d/17/688626d192d7261bbbf98846fc98995726bddc2c945344b65bec3a29d731/pillow-12.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6", size = 7033367, upload-time = "2026-02-11T04:21:03.536Z" }, - { url = "https://files.pythonhosted.org/packages/ed/fe/a0ef1f73f939b0eca03ee2c108d0043a87468664770612602c63266a43c4/pillow-12.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523", size = 2453811, upload-time = "2026-02-11T04:21:05.116Z" }, - { url = "https://files.pythonhosted.org/packages/d5/11/6db24d4bd7685583caeae54b7009584e38da3c3d4488ed4cd25b439de486/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d242e8ac078781f1de88bf823d70c1a9b3c7950a44cdf4b7c012e22ccbcd8e4e", size = 4062689, upload-time = "2026-02-11T04:21:06.804Z" }, - { url = "https://files.pythonhosted.org/packages/33/c0/ce6d3b1fe190f0021203e0d9b5b99e57843e345f15f9ef22fcd43842fd21/pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:02f84dfad02693676692746df05b89cf25597560db2857363a208e393429f5e9", size = 4138535, upload-time = "2026-02-11T04:21:08.452Z" }, - { url = "https://files.pythonhosted.org/packages/a0/c6/d5eb6a4fb32a3f9c21a8c7613ec706534ea1cf9f4b3663e99f0d83f6fca8/pillow-12.1.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e65498daf4b583091ccbb2556c7000abf0f3349fcd57ef7adc9a84a394ed29f6", size = 3601364, upload-time = "2026-02-11T04:21:10.194Z" }, - { url = "https://files.pythonhosted.org/packages/14/a1/16c4b823838ba4c9c52c0e6bbda903a3fe5a1bdbf1b8eb4fff7156f3e318/pillow-12.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c6db3b84c87d48d0088943bf33440e0c42370b99b1c2a7989216f7b42eede60", size = 5262561, upload-time = "2026-02-11T04:21:11.742Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ad/ad9dc98ff24f485008aa5cdedaf1a219876f6f6c42a4626c08bc4e80b120/pillow-12.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b7e5304e34942bf62e15184219a7b5ad4ff7f3bb5cca4d984f37df1a0e1aee2", size = 4657460, upload-time = "2026-02-11T04:21:13.786Z" }, - { url = "https://files.pythonhosted.org/packages/9e/1b/f1a4ea9a895b5732152789326202a82464d5254759fbacae4deea3069334/pillow-12.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:18e5bddd742a44b7e6b1e773ab5db102bd7a94c32555ba656e76d319d19c3850", size = 6232698, upload-time = "2026-02-11T04:21:15.949Z" }, - { url = "https://files.pythonhosted.org/packages/95/f4/86f51b8745070daf21fd2e5b1fe0eb35d4db9ca26e6d58366562fb56a743/pillow-12.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc44ef1f3de4f45b50ccf9136999d71abb99dca7706bc75d222ed350b9fd2289", size = 8041706, upload-time = "2026-02-11T04:21:17.723Z" }, - { url = "https://files.pythonhosted.org/packages/29/9b/d6ecd956bb1266dd1045e995cce9b8d77759e740953a1c9aad9502a0461e/pillow-12.1.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a8eb7ed8d4198bccbd07058416eeec51686b498e784eda166395a23eb99138e", size = 6346621, upload-time = "2026-02-11T04:21:19.547Z" }, - { url = "https://files.pythonhosted.org/packages/71/24/538bff45bde96535d7d998c6fed1a751c75ac7c53c37c90dc2601b243893/pillow-12.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47b94983da0c642de92ced1702c5b6c292a84bd3a8e1d1702ff923f183594717", size = 7038069, upload-time = "2026-02-11T04:21:21.378Z" }, - { url = "https://files.pythonhosted.org/packages/94/0e/58cb1a6bc48f746bc4cb3adb8cabff73e2742c92b3bf7a220b7cf69b9177/pillow-12.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:518a48c2aab7ce596d3bf79d0e275661b846e86e4d0e7dec34712c30fe07f02a", size = 6460040, upload-time = "2026-02-11T04:21:23.148Z" }, - { url = "https://files.pythonhosted.org/packages/6c/57/9045cb3ff11eeb6c1adce3b2d60d7d299d7b273a2e6c8381a524abfdc474/pillow-12.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a550ae29b95c6dc13cf69e2c9dc5747f814c54eeb2e32d683e5e93af56caa029", size = 7164523, upload-time = "2026-02-11T04:21:25.01Z" }, - { url = "https://files.pythonhosted.org/packages/73/f2/9be9cb99f2175f0d4dbadd6616ce1bf068ee54a28277ea1bf1fbf729c250/pillow-12.1.1-cp313-cp313-win32.whl", hash = "sha256:a003d7422449f6d1e3a34e3dd4110c22148336918ddbfc6a32581cd54b2e0b2b", size = 6332552, upload-time = "2026-02-11T04:21:27.238Z" }, - { url = "https://files.pythonhosted.org/packages/3f/eb/b0834ad8b583d7d9d42b80becff092082a1c3c156bb582590fcc973f1c7c/pillow-12.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:344cf1e3dab3be4b1fa08e449323d98a2a3f819ad20f4b22e77a0ede31f0faa1", size = 7040108, upload-time = "2026-02-11T04:21:29.462Z" }, - { url = "https://files.pythonhosted.org/packages/d5/7d/fc09634e2aabdd0feabaff4a32f4a7d97789223e7c2042fd805ea4b4d2c2/pillow-12.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c0dd1636633e7e6a0afe7bf6a51a14992b7f8e60de5789018ebbdfae55b040a", size = 2453712, upload-time = "2026-02-11T04:21:31.072Z" }, - { url = "https://files.pythonhosted.org/packages/19/2a/b9d62794fc8a0dd14c1943df68347badbd5511103e0d04c035ffe5cf2255/pillow-12.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0330d233c1a0ead844fc097a7d16c0abff4c12e856c0b325f231820fee1f39da", size = 5264880, upload-time = "2026-02-11T04:21:32.865Z" }, - { url = "https://files.pythonhosted.org/packages/26/9d/e03d857d1347fa5ed9247e123fcd2a97b6220e15e9cb73ca0a8d91702c6e/pillow-12.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dae5f21afb91322f2ff791895ddd8889e5e947ff59f71b46041c8ce6db790bc", size = 4660616, upload-time = "2026-02-11T04:21:34.97Z" }, - { url = "https://files.pythonhosted.org/packages/f7/ec/8a6d22afd02570d30954e043f09c32772bfe143ba9285e2fdb11284952cd/pillow-12.1.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e0c664be47252947d870ac0d327fea7e63985a08794758aa8af5b6cb6ec0c9c", size = 6269008, upload-time = "2026-02-11T04:21:36.623Z" }, - { url = "https://files.pythonhosted.org/packages/3d/1d/6d875422c9f28a4a361f495a5f68d9de4a66941dc2c619103ca335fa6446/pillow-12.1.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:691ab2ac363b8217f7d31b3497108fb1f50faab2f75dfb03284ec2f217e87bf8", size = 8073226, upload-time = "2026-02-11T04:21:38.585Z" }, - { url = "https://files.pythonhosted.org/packages/a1/cd/134b0b6ee5eda6dc09e25e24b40fdafe11a520bc725c1d0bbaa5e00bf95b/pillow-12.1.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9e8064fb1cc019296958595f6db671fba95209e3ceb0c4734c9baf97de04b20", size = 6380136, upload-time = "2026-02-11T04:21:40.562Z" }, - { url = "https://files.pythonhosted.org/packages/7a/a9/7628f013f18f001c1b98d8fffe3452f306a70dc6aba7d931019e0492f45e/pillow-12.1.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:472a8d7ded663e6162dafdf20015c486a7009483ca671cece7a9279b512fcb13", size = 7067129, upload-time = "2026-02-11T04:21:42.521Z" }, - { url = "https://files.pythonhosted.org/packages/1e/f8/66ab30a2193b277785601e82ee2d49f68ea575d9637e5e234faaa98efa4c/pillow-12.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:89b54027a766529136a06cfebeecb3a04900397a3590fd252160b888479517bf", size = 6491807, upload-time = "2026-02-11T04:21:44.22Z" }, - { url = "https://files.pythonhosted.org/packages/da/0b/a877a6627dc8318fdb84e357c5e1a758c0941ab1ddffdafd231983788579/pillow-12.1.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:86172b0831b82ce4f7877f280055892b31179e1576aa00d0df3bb1bbf8c3e524", size = 7190954, upload-time = "2026-02-11T04:21:46.114Z" }, - { url = "https://files.pythonhosted.org/packages/83/43/6f732ff85743cf746b1361b91665d9f5155e1483817f693f8d57ea93147f/pillow-12.1.1-cp313-cp313t-win32.whl", hash = "sha256:44ce27545b6efcf0fdbdceb31c9a5bdea9333e664cda58a7e674bb74608b3986", size = 6336441, upload-time = "2026-02-11T04:21:48.22Z" }, - { url = "https://files.pythonhosted.org/packages/3b/44/e865ef3986611bb75bfabdf94a590016ea327833f434558801122979cd0e/pillow-12.1.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a285e3eb7a5a45a2ff504e31f4a8d1b12ef62e84e5411c6804a42197c1cf586c", size = 7045383, upload-time = "2026-02-11T04:21:50.015Z" }, - { url = "https://files.pythonhosted.org/packages/a8/c6/f4fb24268d0c6908b9f04143697ea18b0379490cb74ba9e8d41b898bd005/pillow-12.1.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cc7d296b5ea4d29e6570dabeaed58d31c3fea35a633a69679fb03d7664f43fb3", size = 2456104, upload-time = "2026-02-11T04:21:51.633Z" }, - { url = "https://files.pythonhosted.org/packages/03/d0/bebb3ffbf31c5a8e97241476c4cf8b9828954693ce6744b4a2326af3e16b/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af", size = 4062652, upload-time = "2026-02-11T04:21:53.19Z" }, - { url = "https://files.pythonhosted.org/packages/2d/c0/0e16fb0addda4851445c28f8350d8c512f09de27bbb0d6d0bbf8b6709605/pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f", size = 4138823, upload-time = "2026-02-11T04:22:03.088Z" }, - { url = "https://files.pythonhosted.org/packages/6b/fb/6170ec655d6f6bb6630a013dd7cf7bc218423d7b5fa9071bf63dc32175ae/pillow-12.1.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642", size = 3601143, upload-time = "2026-02-11T04:22:04.909Z" }, - { url = "https://files.pythonhosted.org/packages/59/04/dc5c3f297510ba9a6837cbb318b87dd2b8f73eb41a43cc63767f65cb599c/pillow-12.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd", size = 5266254, upload-time = "2026-02-11T04:22:07.656Z" }, - { url = "https://files.pythonhosted.org/packages/05/30/5db1236b0d6313f03ebf97f5e17cda9ca060f524b2fcc875149a8360b21c/pillow-12.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202", size = 4657499, upload-time = "2026-02-11T04:22:09.613Z" }, - { url = "https://files.pythonhosted.org/packages/6f/18/008d2ca0eb612e81968e8be0bbae5051efba24d52debf930126d7eaacbba/pillow-12.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f", size = 6232137, upload-time = "2026-02-11T04:22:11.434Z" }, - { url = "https://files.pythonhosted.org/packages/70/f1/f14d5b8eeb4b2cd62b9f9f847eb6605f103df89ef619ac68f92f748614ea/pillow-12.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f", size = 8042721, upload-time = "2026-02-11T04:22:13.321Z" }, - { url = "https://files.pythonhosted.org/packages/5a/d6/17824509146e4babbdabf04d8171491fa9d776f7061ff6e727522df9bd03/pillow-12.1.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f", size = 6347798, upload-time = "2026-02-11T04:22:15.449Z" }, - { url = "https://files.pythonhosted.org/packages/d1/ee/c85a38a9ab92037a75615aba572c85ea51e605265036e00c5b67dfafbfe2/pillow-12.1.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e", size = 7039315, upload-time = "2026-02-11T04:22:17.24Z" }, - { url = "https://files.pythonhosted.org/packages/ec/f3/bc8ccc6e08a148290d7523bde4d9a0d6c981db34631390dc6e6ec34cacf6/pillow-12.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0", size = 6462360, upload-time = "2026-02-11T04:22:19.111Z" }, - { url = "https://files.pythonhosted.org/packages/f6/ab/69a42656adb1d0665ab051eec58a41f169ad295cf81ad45406963105408f/pillow-12.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb", size = 7165438, upload-time = "2026-02-11T04:22:21.041Z" }, - { url = "https://files.pythonhosted.org/packages/02/46/81f7aa8941873f0f01d4b55cc543b0a3d03ec2ee30d617a0448bf6bd6dec/pillow-12.1.1-cp314-cp314-win32.whl", hash = "sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f", size = 6431503, upload-time = "2026-02-11T04:22:22.833Z" }, - { url = "https://files.pythonhosted.org/packages/40/72/4c245f7d1044b67affc7f134a09ea619d4895333d35322b775b928180044/pillow-12.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15", size = 7176748, upload-time = "2026-02-11T04:22:24.64Z" }, - { url = "https://files.pythonhosted.org/packages/e4/ad/8a87bdbe038c5c698736e3348af5c2194ffb872ea52f11894c95f9305435/pillow-12.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f", size = 2544314, upload-time = "2026-02-11T04:22:26.685Z" }, - { url = "https://files.pythonhosted.org/packages/6c/9d/efd18493f9de13b87ede7c47e69184b9e859e4427225ea962e32e56a49bc/pillow-12.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8", size = 5268612, upload-time = "2026-02-11T04:22:29.884Z" }, - { url = "https://files.pythonhosted.org/packages/f8/f1/4f42eb2b388eb2ffc660dcb7f7b556c1015c53ebd5f7f754965ef997585b/pillow-12.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9", size = 4660567, upload-time = "2026-02-11T04:22:31.799Z" }, - { url = "https://files.pythonhosted.org/packages/01/54/df6ef130fa43e4b82e32624a7b821a2be1c5653a5fdad8469687a7db4e00/pillow-12.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60", size = 6269951, upload-time = "2026-02-11T04:22:33.921Z" }, - { url = "https://files.pythonhosted.org/packages/a9/48/618752d06cc44bb4aae8ce0cd4e6426871929ed7b46215638088270d9b34/pillow-12.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7", size = 8074769, upload-time = "2026-02-11T04:22:35.877Z" }, - { url = "https://files.pythonhosted.org/packages/c3/bd/f1d71eb39a72fa088d938655afba3e00b38018d052752f435838961127d8/pillow-12.1.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f", size = 6381358, upload-time = "2026-02-11T04:22:37.698Z" }, - { url = "https://files.pythonhosted.org/packages/64/ef/c784e20b96674ed36a5af839305f55616f8b4f8aa8eeccf8531a6e312243/pillow-12.1.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586", size = 7068558, upload-time = "2026-02-11T04:22:39.597Z" }, - { url = "https://files.pythonhosted.org/packages/73/cb/8059688b74422ae61278202c4e1ad992e8a2e7375227be0a21c6b87ca8d5/pillow-12.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce", size = 6493028, upload-time = "2026-02-11T04:22:42.73Z" }, - { url = "https://files.pythonhosted.org/packages/c6/da/e3c008ed7d2dd1f905b15949325934510b9d1931e5df999bb15972756818/pillow-12.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8", size = 7191940, upload-time = "2026-02-11T04:22:44.543Z" }, - { url = "https://files.pythonhosted.org/packages/01/4a/9202e8d11714c1fc5951f2e1ef362f2d7fbc595e1f6717971d5dd750e969/pillow-12.1.1-cp314-cp314t-win32.whl", hash = "sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36", size = 6438736, upload-time = "2026-02-11T04:22:46.347Z" }, - { url = "https://files.pythonhosted.org/packages/f3/ca/cbce2327eb9885476b3957b2e82eb12c866a8b16ad77392864ad601022ce/pillow-12.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b", size = 7182894, upload-time = "2026-02-11T04:22:48.114Z" }, - { url = "https://files.pythonhosted.org/packages/ec/d2/de599c95ba0a973b94410477f8bf0b6f0b5e67360eb89bcb1ad365258beb/pillow-12.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334", size = 2546446, upload-time = "2026-02-11T04:22:50.342Z" }, +version = "11.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" }, + { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" }, + { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" }, + { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" }, + { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" }, + { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" }, + { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" }, + { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" }, + { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" }, + { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" }, + { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" }, + { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" }, + { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" }, + { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" }, + { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" }, + { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" }, + { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" }, + { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" }, + { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" }, + { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" }, + { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" }, + { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" }, + { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" }, + { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" }, + { url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520, upload-time = "2025-07-01T09:15:17.429Z" }, + { url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116, upload-time = "2025-07-01T09:15:19.423Z" }, + { url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597, upload-time = "2025-07-03T13:10:38.404Z" }, + { url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246, upload-time = "2025-07-03T13:10:44.987Z" }, + { url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336, upload-time = "2025-07-01T09:15:21.237Z" }, + { url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699, upload-time = "2025-07-01T09:15:23.186Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789, upload-time = "2025-07-01T09:15:25.1Z" }, + { url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386, upload-time = "2025-07-01T09:15:27.378Z" }, + { url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911, upload-time = "2025-07-01T09:15:29.294Z" }, + { url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383, upload-time = "2025-07-01T09:15:31.128Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385, upload-time = "2025-07-01T09:15:33.328Z" }, + { url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129, upload-time = "2025-07-01T09:15:35.194Z" }, + { url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580, upload-time = "2025-07-01T09:15:37.114Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860, upload-time = "2025-07-03T13:10:50.248Z" }, + { url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694, upload-time = "2025-07-03T13:10:56.432Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888, upload-time = "2025-07-01T09:15:39.436Z" }, + { url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330, upload-time = "2025-07-01T09:15:41.269Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089, upload-time = "2025-07-01T09:15:43.13Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206, upload-time = "2025-07-01T09:15:44.937Z" }, + { url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370, upload-time = "2025-07-01T09:15:46.673Z" }, + { url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500, upload-time = "2025-07-01T09:15:48.512Z" }, + { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" }, ] [[package]] @@ -1607,6 +1880,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/1b/f7ea6cde25621cd9236541c66ff018f4268012a534ec31032bcb187dc5e7/proglog-0.1.12-py3-none-any.whl", hash = "sha256:ccaafce51e80a81c65dc907a460c07ccb8ec1f78dc660cfd8f9ec3a22f01b84c", size = 6337, upload-time = "2025-05-09T14:36:16.798Z" }, ] +[[package]] +name = "proto-plus" +version = "1.27.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/81/0d/94dfe80193e79d55258345901acd2917523d56e8381bc4dee7fd38e3868a/proto_plus-1.27.2.tar.gz", hash = "sha256:b2adde53adadf75737c44d3dcb0104fde65250dfc83ad59168b4aa3e574b6a24", size = 57204, upload-time = "2026-03-26T22:18:57.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/f3/1fba73eeffafc998a25d59703b63f8be4fe8a5cb12eaff7386a0ba0f7125/proto_plus-1.27.2-py3-none-any.whl", hash = "sha256:6432f75893d3b9e70b9c412f1d2f03f65b11fb164b793d14ae2ca01821d22718", size = 50450, upload-time = "2026-03-26T22:13:42.927Z" }, +] + +[[package]] +name = "protobuf" +version = "6.33.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/70/e908e9c5e52ef7c3a6c7902c9dfbb34c7e29c25d2f81ade3856445fd5c94/protobuf-6.33.6.tar.gz", hash = "sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135", size = 444531, upload-time = "2026-03-18T19:05:00.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/9f/2f509339e89cfa6f6a4c4ff50438db9ca488dec341f7e454adad60150b00/protobuf-6.33.6-cp310-abi3-win32.whl", hash = "sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3", size = 425739, upload-time = "2026-03-18T19:04:48.373Z" }, + { url = "https://files.pythonhosted.org/packages/76/5d/683efcd4798e0030c1bab27374fd13a89f7c2515fb1f3123efdfaa5eab57/protobuf-6.33.6-cp310-abi3-win_amd64.whl", hash = "sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326", size = 437089, upload-time = "2026-03-18T19:04:50.381Z" }, + { url = "https://files.pythonhosted.org/packages/5c/01/a3c3ed5cd186f39e7880f8303cc51385a198a81469d53d0fdecf1f64d929/protobuf-6.33.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a", size = 427737, upload-time = "2026-03-18T19:04:51.866Z" }, + { url = "https://files.pythonhosted.org/packages/ee/90/b3c01fdec7d2f627b3a6884243ba328c1217ed2d978def5c12dc50d328a3/protobuf-6.33.6-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2", size = 324610, upload-time = "2026-03-18T19:04:53.096Z" }, + { url = "https://files.pythonhosted.org/packages/9b/ca/25afc144934014700c52e05103c2421997482d561f3101ff352e1292fb81/protobuf-6.33.6-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3", size = 339381, upload-time = "2026-03-18T19:04:54.616Z" }, + { url = "https://files.pythonhosted.org/packages/16/92/d1e32e3e0d894fe00b15ce28ad4944ab692713f2e7f0a99787405e43533a/protobuf-6.33.6-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593", size = 323436, upload-time = "2026-03-18T19:04:55.768Z" }, + { url = "https://files.pythonhosted.org/packages/c4/72/02445137af02769918a93807b2b7890047c32bfb9f90371cbc12688819eb/protobuf-6.33.6-py3-none-any.whl", hash = "sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901", size = 170656, upload-time = "2026-03-18T19:04:59.826Z" }, +] + [[package]] name = "psutil" version = "7.2.2" @@ -1637,46 +1937,51 @@ wheels = [ [[package]] name = "psychopy" -version = "2025.1.1" +version = "2022.2.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "arabic-reshaper" }, { name = "astunparse" }, { name = "cryptography" }, { name = "distro", marker = "sys_platform == 'linux'" }, + { name = "egi-pynetstation" }, { name = "esprima" }, { name = "ffpyplayer" }, { name = "freetype-py" }, - { name = "future" }, { name = "gevent" }, { name = "gitpython" }, + { name = "glfw" }, + { name = "google-api-core" }, + { name = "google-auth" }, + { name = "google-cloud" }, + { name = "google-cloud-speech" }, + { name = "googleapis-common-protos" }, { name = "imageio" }, { name = "imageio-ffmpeg" }, { name = "javascripthon" }, { name = "jedi" }, + { name = "json-tricks" }, { name = "markdown-it-py" }, { name = "matplotlib" }, - { name = "meshpy" }, { name = "moviepy" }, { name = "msgpack" }, { name = "msgpack-numpy" }, { name = "numpy" }, - { name = "opencv-python" }, { name = "openpyxl" }, - { name = "packaging" }, { name = "pandas" }, { name = "pillow" }, { name = "psutil" }, - { name = "psychtoolbox", marker = "platform_machine != 'arm64'" }, - { name = "pyarrow" }, - { name = "pyglet", version = "1.4.11", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform == 'win32'" }, - { name = "pyglet", version = "1.5.27", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'win32'" }, + { name = "psychtoolbox" }, + { name = "pygame" }, + { name = "pyglet", version = "1.4.11", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'darwin'" }, + { name = "pyglet", version = "2.1.14", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform == 'darwin'" }, + { name = "pyo" }, { name = "pyobjc", marker = "sys_platform == 'darwin'" }, { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, - { name = "pyparallel", marker = "sys_platform != 'darwin'" }, + { name = "pyparallel", marker = "sys_platform == 'linux'" }, { name = "pypiwin32", marker = "sys_platform == 'win32'" }, - { name = "pyqt6" }, + { name = "pyqmix", marker = "sys_platform == 'win32'" }, { name = "pyserial" }, { name = "python-bidi" }, { name = "python-gitlab" }, @@ -1689,19 +1994,17 @@ dependencies = [ { name = "questplus" }, { name = "requests" }, { name = "scipy" }, - { name = "setuptools" }, + { name = "sounddevice" }, { name = "soundfile" }, + { name = "speechrecognition" }, { name = "tables" }, { name = "ujson" }, - { name = "websockets" }, - { name = "wxpython" }, - { name = "xmlschema" }, - { name = "zeroconf", marker = "sys_platform == 'darwin'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/2f/d24a6ac493475ffdcc66b0b8ebe2127f9306f98ef2411982d8b836ab31df/psychopy-2025.1.1.tar.gz", hash = "sha256:c70ce04d45acfd75d468fc9978585a062b8e29209089b8faa78b46ea55409139", size = 44859978, upload-time = "2025-05-12T13:43:33.936Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/0f/55e49ebc1d33b321e53e7fa57b445fc035a5c401d46b17fa087fb603ed35/psychopy-2025.1.1-py3-none-any.whl", hash = "sha256:532f2593283a519a37159d413870fe284bfa94dc171906bd5bc4fcd8a3451583", size = 46478207, upload-time = "2025-05-12T13:43:30.078Z" }, + { name = "websocket-client" }, + { name = "wxpython", version = "4.1.1", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform == 'darwin'" }, + { name = "wxpython", version = "4.2.5", source = { registry = "https://pypi.org/simple" }, marker = "sys_platform != 'darwin'" }, + { name = "xlrd" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/4d/77/61161b58f2828749f604063214e267ffa886004c015ff64b64ce92b21e97/PsychoPy-2022.2.4.zip", hash = "sha256:2361ae7694bf757042ee44fba7e9b165f8eea4ae7392ee8388c37f04a8843d87", size = 25785748, upload-time = "2022-08-18T15:22:15.755Z" } [[package]] name = "psychtoolbox" @@ -1727,46 +2030,24 @@ wheels = [ ] [[package]] -name = "pyarrow" -version = "23.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/22/134986a4cc224d593c1afde5494d18ff629393d74cc2eddb176669f234a4/pyarrow-23.0.1.tar.gz", hash = "sha256:b8c5873e33440b2bc2f4a79d2b47017a89c5a24116c055625e6f2ee50523f019", size = 1167336, upload-time = "2026-02-16T10:14:12.39Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/4b/4166bb5abbfe6f750fc60ad337c43ecf61340fa52ab386da6e8dbf9e63c4/pyarrow-23.0.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:f4b0dbfa124c0bb161f8b5ebb40f1a680b70279aa0c9901d44a2b5a20806039f", size = 34214575, upload-time = "2026-02-16T10:09:56.225Z" }, - { url = "https://files.pythonhosted.org/packages/e1/da/3f941e3734ac8088ea588b53e860baeddac8323ea40ce22e3d0baa865cc9/pyarrow-23.0.1-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:7707d2b6673f7de054e2e83d59f9e805939038eebe1763fe811ee8fa5c0cd1a7", size = 35832540, upload-time = "2026-02-16T10:10:03.428Z" }, - { url = "https://files.pythonhosted.org/packages/88/7c/3d841c366620e906d54430817531b877ba646310296df42ef697308c2705/pyarrow-23.0.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:86ff03fb9f1a320266e0de855dee4b17da6794c595d207f89bba40d16b5c78b9", size = 44470940, upload-time = "2026-02-16T10:10:10.704Z" }, - { url = "https://files.pythonhosted.org/packages/2c/a5/da83046273d990f256cb79796a190bbf7ec999269705ddc609403f8c6b06/pyarrow-23.0.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:813d99f31275919c383aab17f0f455a04f5a429c261cc411b1e9a8f5e4aaaa05", size = 47586063, upload-time = "2026-02-16T10:10:17.95Z" }, - { url = "https://files.pythonhosted.org/packages/5b/3c/b7d2ebcff47a514f47f9da1e74b7949138c58cfeb108cdd4ee62f43f0cf3/pyarrow-23.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bf5842f960cddd2ef757d486041d57c96483efc295a8c4a0e20e704cbbf39c67", size = 48173045, upload-time = "2026-02-16T10:10:25.363Z" }, - { url = "https://files.pythonhosted.org/packages/43/b2/b40961262213beaba6acfc88698eb773dfce32ecdf34d19291db94c2bd73/pyarrow-23.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564baf97c858ecc03ec01a41062e8f4698abc3e6e2acd79c01c2e97880a19730", size = 50621741, upload-time = "2026-02-16T10:10:33.477Z" }, - { url = "https://files.pythonhosted.org/packages/f6/70/1fdda42d65b28b078e93d75d371b2185a61da89dda4def8ba6ba41ebdeb4/pyarrow-23.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:07deae7783782ac7250989a7b2ecde9b3c343a643f82e8a4df03d93b633006f0", size = 27620678, upload-time = "2026-02-16T10:10:39.31Z" }, - { url = "https://files.pythonhosted.org/packages/47/10/2cbe4c6f0fb83d2de37249567373d64327a5e4d8db72f486db42875b08f6/pyarrow-23.0.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:6b8fda694640b00e8af3c824f99f789e836720aa8c9379fb435d4c4953a756b8", size = 34210066, upload-time = "2026-02-16T10:10:45.487Z" }, - { url = "https://files.pythonhosted.org/packages/cb/4f/679fa7e84dadbaca7a65f7cdba8d6c83febbd93ca12fa4adf40ba3b6362b/pyarrow-23.0.1-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:8ff51b1addc469b9444b7c6f3548e19dc931b172ab234e995a60aea9f6e6025f", size = 35825526, upload-time = "2026-02-16T10:10:52.266Z" }, - { url = "https://files.pythonhosted.org/packages/f9/63/d2747d930882c9d661e9398eefc54f15696547b8983aaaf11d4a2e8b5426/pyarrow-23.0.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:71c5be5cbf1e1cb6169d2a0980850bccb558ddc9b747b6206435313c47c37677", size = 44473279, upload-time = "2026-02-16T10:11:01.557Z" }, - { url = "https://files.pythonhosted.org/packages/b3/93/10a48b5e238de6d562a411af6467e71e7aedbc9b87f8d3a35f1560ae30fb/pyarrow-23.0.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:9b6f4f17b43bc39d56fec96e53fe89d94bac3eb134137964371b45352d40d0c2", size = 47585798, upload-time = "2026-02-16T10:11:09.401Z" }, - { url = "https://files.pythonhosted.org/packages/5c/20/476943001c54ef078dbf9542280e22741219a184a0632862bca4feccd666/pyarrow-23.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fc13fc6c403d1337acab46a2c4346ca6c9dec5780c3c697cf8abfd5e19b6b37", size = 48179446, upload-time = "2026-02-16T10:11:17.781Z" }, - { url = "https://files.pythonhosted.org/packages/4b/b6/5dd0c47b335fcd8edba9bfab78ad961bd0fd55ebe53468cc393f45e0be60/pyarrow-23.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5c16ed4f53247fa3ffb12a14d236de4213a4415d127fe9cebed33d51671113e2", size = 50623972, upload-time = "2026-02-16T10:11:26.185Z" }, - { url = "https://files.pythonhosted.org/packages/d5/09/a532297c9591a727d67760e2e756b83905dd89adb365a7f6e9c72578bcc1/pyarrow-23.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:cecfb12ef629cf6be0b1887f9f86463b0dd3dc3195ae6224e74006be4736035a", size = 27540749, upload-time = "2026-02-16T10:12:23.297Z" }, - { url = "https://files.pythonhosted.org/packages/a5/8e/38749c4b1303e6ae76b3c80618f84861ae0c55dd3c2273842ea6f8258233/pyarrow-23.0.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:29f7f7419a0e30264ea261fdc0e5fe63ce5a6095003db2945d7cd78df391a7e1", size = 34471544, upload-time = "2026-02-16T10:11:32.535Z" }, - { url = "https://files.pythonhosted.org/packages/a3/73/f237b2bc8c669212f842bcfd842b04fc8d936bfc9d471630569132dc920d/pyarrow-23.0.1-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:33d648dc25b51fd8055c19e4261e813dfc4d2427f068bcecc8b53d01b81b0500", size = 35949911, upload-time = "2026-02-16T10:11:39.813Z" }, - { url = "https://files.pythonhosted.org/packages/0c/86/b912195eee0903b5611bf596833def7d146ab2d301afeb4b722c57ffc966/pyarrow-23.0.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:cd395abf8f91c673dd3589cadc8cc1ee4e8674fa61b2e923c8dd215d9c7d1f41", size = 44520337, upload-time = "2026-02-16T10:11:47.764Z" }, - { url = "https://files.pythonhosted.org/packages/69/c2/f2a717fb824f62d0be952ea724b4f6f9372a17eed6f704b5c9526f12f2f1/pyarrow-23.0.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:00be9576d970c31defb5c32eb72ef585bf600ef6d0a82d5eccaae96639cf9d07", size = 47548944, upload-time = "2026-02-16T10:11:56.607Z" }, - { url = "https://files.pythonhosted.org/packages/84/a7/90007d476b9f0dc308e3bc57b832d004f848fd6c0da601375d20d92d1519/pyarrow-23.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c2139549494445609f35a5cda4eb94e2c9e4d704ce60a095b342f82460c73a83", size = 48236269, upload-time = "2026-02-16T10:12:04.47Z" }, - { url = "https://files.pythonhosted.org/packages/b0/3f/b16fab3e77709856eb6ac328ce35f57a6d4a18462c7ca5186ef31b45e0e0/pyarrow-23.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:7044b442f184d84e2351e5084600f0d7343d6117aabcbc1ac78eb1ae11eb4125", size = 50604794, upload-time = "2026-02-16T10:12:11.797Z" }, - { url = "https://files.pythonhosted.org/packages/e9/a1/22df0620a9fac31d68397a75465c344e83c3dfe521f7612aea33e27ab6c0/pyarrow-23.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a35581e856a2fafa12f3f54fce4331862b1cfb0bef5758347a858a4aa9d6bae8", size = 27660642, upload-time = "2026-02-16T10:12:17.746Z" }, - { url = "https://files.pythonhosted.org/packages/8d/1b/6da9a89583ce7b23ac611f183ae4843cd3a6cf54f079549b0e8c14031e73/pyarrow-23.0.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:5df1161da23636a70838099d4aaa65142777185cc0cdba4037a18cee7d8db9ca", size = 34238755, upload-time = "2026-02-16T10:12:32.819Z" }, - { url = "https://files.pythonhosted.org/packages/ae/b5/d58a241fbe324dbaeb8df07be6af8752c846192d78d2272e551098f74e88/pyarrow-23.0.1-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:fa8e51cb04b9f8c9c5ace6bab63af9a1f88d35c0d6cbf53e8c17c098552285e1", size = 35847826, upload-time = "2026-02-16T10:12:38.949Z" }, - { url = "https://files.pythonhosted.org/packages/54/a5/8cbc83f04aba433ca7b331b38f39e000efd9f0c7ce47128670e737542996/pyarrow-23.0.1-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:0b95a3994f015be13c63148fef8832e8a23938128c185ee951c98908a696e0eb", size = 44536859, upload-time = "2026-02-16T10:12:45.467Z" }, - { url = "https://files.pythonhosted.org/packages/36/2e/c0f017c405fcdc252dbccafbe05e36b0d0eb1ea9a958f081e01c6972927f/pyarrow-23.0.1-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:4982d71350b1a6e5cfe1af742c53dfb759b11ce14141870d05d9e540d13bc5d1", size = 47614443, upload-time = "2026-02-16T10:12:55.525Z" }, - { url = "https://files.pythonhosted.org/packages/af/6b/2314a78057912f5627afa13ba43809d9d653e6630859618b0fd81a4e0759/pyarrow-23.0.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c250248f1fe266db627921c89b47b7c06fee0489ad95b04d50353537d74d6886", size = 48232991, upload-time = "2026-02-16T10:13:04.729Z" }, - { url = "https://files.pythonhosted.org/packages/40/f2/1bcb1d3be3460832ef3370d621142216e15a2c7c62602a4ea19ec240dd64/pyarrow-23.0.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5f4763b83c11c16e5f4c15601ba6dfa849e20723b46aa2617cb4bffe8768479f", size = 50645077, upload-time = "2026-02-16T10:13:14.147Z" }, - { url = "https://files.pythonhosted.org/packages/eb/3f/b1da7b61cd66566a4d4c8383d376c606d1c34a906c3f1cb35c479f59d1aa/pyarrow-23.0.1-cp314-cp314-win_amd64.whl", hash = "sha256:3a4c85ef66c134161987c17b147d6bffdca4566f9a4c1d81a0a01cdf08414ea5", size = 28234271, upload-time = "2026-02-16T10:14:09.397Z" }, - { url = "https://files.pythonhosted.org/packages/b5/78/07f67434e910a0f7323269be7bfbf58699bd0c1d080b18a1ab49ba943fe8/pyarrow-23.0.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:17cd28e906c18af486a499422740298c52d7c6795344ea5002a7720b4eadf16d", size = 34488692, upload-time = "2026-02-16T10:13:21.541Z" }, - { url = "https://files.pythonhosted.org/packages/50/76/34cf7ae93ece1f740a04910d9f7e80ba166b9b4ab9596a953e9e62b90fe1/pyarrow-23.0.1-cp314-cp314t-macosx_12_0_x86_64.whl", hash = "sha256:76e823d0e86b4fb5e1cf4a58d293036e678b5a4b03539be933d3b31f9406859f", size = 35964383, upload-time = "2026-02-16T10:13:28.63Z" }, - { url = "https://files.pythonhosted.org/packages/46/90/459b827238936d4244214be7c684e1b366a63f8c78c380807ae25ed92199/pyarrow-23.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:a62e1899e3078bf65943078b3ad2a6ddcacf2373bc06379aac61b1e548a75814", size = 44538119, upload-time = "2026-02-16T10:13:35.506Z" }, - { url = "https://files.pythonhosted.org/packages/28/a1/93a71ae5881e99d1f9de1d4554a87be37da11cd6b152239fb5bd924fdc64/pyarrow-23.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:df088e8f640c9fae3b1f495b3c64755c4e719091caf250f3a74d095ddf3c836d", size = 47571199, upload-time = "2026-02-16T10:13:42.504Z" }, - { url = "https://files.pythonhosted.org/packages/88/a3/d2c462d4ef313521eaf2eff04d204ac60775263f1fb08c374b543f79f610/pyarrow-23.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:46718a220d64677c93bc243af1d44b55998255427588e400677d7192671845c7", size = 48259435, upload-time = "2026-02-16T10:13:49.226Z" }, - { url = "https://files.pythonhosted.org/packages/cc/f1/11a544b8c3d38a759eb3fbb022039117fd633e9a7b19e4841cc3da091915/pyarrow-23.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a09f3876e87f48bc2f13583ab551f0379e5dfb83210391e68ace404181a20690", size = 50629149, upload-time = "2026-02-16T10:13:57.238Z" }, - { url = "https://files.pythonhosted.org/packages/50/f2/c0e76a0b451ffdf0cf788932e182758eb7558953f4f27f1aff8e2518b653/pyarrow-23.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:527e8d899f14bd15b740cd5a54ad56b7f98044955373a17179d5956ddb93d9ce", size = 28365807, upload-time = "2026-02-16T10:14:03.892Z" }, +name = "pyasn1" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/5f/6583902b6f79b399c9c40674ac384fd9cd77805f9e6205075f828ef11fb2/pyasn1-0.6.3.tar.gz", hash = "sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf", size = 148685, upload-time = "2026-03-17T01:06:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/a0/7d793dce3fa811fe047d6ae2431c672364b462850c6235ae306c0efd025f/pyasn1-0.6.3-py3-none-any.whl", hash = "sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde", size = 83997, upload-time = "2026-03-17T01:06:52.036Z" }, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, ] [[package]] @@ -1814,16 +2095,45 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c2/2f/81d580a0fb83baeb066698975cb14a618bdbed7720678566f1b046a95fe8/pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f", size = 63551, upload-time = "2025-06-20T18:45:26.937Z" }, ] +[[package]] +name = "pygame" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/cc/08bba60f00541f62aaa252ce0cfbd60aebd04616c0b9574f755b583e45ae/pygame-2.6.1.tar.gz", hash = "sha256:56fb02ead529cee00d415c3e007f75e0780c655909aaa8e8bf616ee09c9feb1f", size = 14808125, upload-time = "2024-09-29T13:41:34.698Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/16/2c602c332f45ff9526d61f6bd764db5096ff9035433e2172e2d2cadae8db/pygame-2.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4ee7f2771f588c966fa2fa8b829be26698c9b4836f82ede5e4edc1a68594942e", size = 13118279, upload-time = "2024-09-29T14:26:30.427Z" }, + { url = "https://files.pythonhosted.org/packages/cd/53/77ccbc384b251c6e34bfd2e734c638233922449a7844e3c7a11ef91cee39/pygame-2.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c8040ea2ab18c6b255af706ec01355c8a6b08dc48d77fd4ee783f8fc46a843bf", size = 12384524, upload-time = "2024-09-29T14:26:49.996Z" }, + { url = "https://files.pythonhosted.org/packages/06/be/3ed337583f010696c3b3435e89a74fb29d0c74d0931e8f33c0a4246307a9/pygame-2.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47a6938de93fa610accd4969e638c2aebcb29b2fca518a84c3a39d91ab47116", size = 13587123, upload-time = "2024-09-29T11:10:50.072Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ca/b015586a450db59313535662991b34d24c1f0c0dc149cc5f496573900f4e/pygame-2.6.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33006f784e1c7d7e466fcb61d5489da59cc5f7eb098712f792a225df1d4e229d", size = 14275532, upload-time = "2024-09-29T11:39:59.356Z" }, + { url = "https://files.pythonhosted.org/packages/b9/f2/d31e6ad42d657af07be2ffd779190353f759a07b51232b9e1d724f2cda46/pygame-2.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1206125f14cae22c44565c9d333607f1d9f59487b1f1432945dfc809aeaa3e88", size = 13952653, upload-time = "2024-09-29T11:40:01.781Z" }, + { url = "https://files.pythonhosted.org/packages/f3/42/8ea2a6979e6fa971702fece1747e862e2256d4a8558fe0da6364dd946c53/pygame-2.6.1-cp312-cp312-win32.whl", hash = "sha256:84fc4054e25262140d09d39e094f6880d730199710829902f0d8ceae0213379e", size = 10252421, upload-time = "2024-09-29T11:14:26.877Z" }, + { url = "https://files.pythonhosted.org/packages/5f/90/7d766d54bb95939725e9a9361f9c06b0cfbe3fe100aa35400f0a461a278a/pygame-2.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:3a9e7396be0d9633831c3f8d5d82dd63ba373ad65599628294b7a4f8a5a01a65", size = 10624591, upload-time = "2024-09-29T11:52:54.489Z" }, + { url = "https://files.pythonhosted.org/packages/e1/91/718acf3e2a9d08a6ddcc96bd02a6f63c99ee7ba14afeaff2a51c987df0b9/pygame-2.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae6039f3a55d800db80e8010f387557b528d34d534435e0871326804df2a62f2", size = 13090765, upload-time = "2024-09-29T14:27:02.377Z" }, + { url = "https://files.pythonhosted.org/packages/0e/c6/9cb315de851a7682d9c7568a41ea042ee98d668cb8deadc1dafcab6116f0/pygame-2.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2a3a1288e2e9b1e5834e425bedd5ba01a3cd4902b5c2bff8ed4a740ccfe98171", size = 12381704, upload-time = "2024-09-29T14:27:10.228Z" }, + { url = "https://files.pythonhosted.org/packages/9f/8f/617a1196e31ae3b46be6949fbaa95b8c93ce15e0544266198c2266cc1b4d/pygame-2.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27eb17e3dc9640e4b4683074f1890e2e879827447770470c2aba9f125f74510b", size = 13581091, upload-time = "2024-09-29T11:30:27.653Z" }, + { url = "https://files.pythonhosted.org/packages/3b/87/2851a564e40a2dad353f1c6e143465d445dab18a95281f9ea458b94f3608/pygame-2.6.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c1623180e70a03c4a734deb9bac50fc9c82942ae84a3a220779062128e75f3b", size = 14273844, upload-time = "2024-09-29T11:40:04.138Z" }, + { url = "https://files.pythonhosted.org/packages/85/b5/aa23aa2e70bcba42c989c02e7228273c30f3b44b9b264abb93eaeff43ad7/pygame-2.6.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef07c0103d79492c21fced9ad68c11c32efa6801ca1920ebfd0f15fb46c78b1c", size = 13951197, upload-time = "2024-09-29T11:40:06.785Z" }, + { url = "https://files.pythonhosted.org/packages/a6/06/29e939b34d3f1354738c7d201c51c250ad7abefefaf6f8332d962ff67c4b/pygame-2.6.1-cp313-cp313-win32.whl", hash = "sha256:3acd8c009317190c2bfd81db681ecef47d5eb108c2151d09596d9c7ea9df5c0e", size = 10249309, upload-time = "2024-09-29T11:10:23.329Z" }, + { url = "https://files.pythonhosted.org/packages/7e/11/17f7f319ca91824b86557e9303e3b7a71991ef17fd45286bf47d7f0a38e6/pygame-2.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:813af4fba5d0b2cb8e58f5d95f7910295c34067dcc290d34f1be59c48bd1ea6a", size = 10620084, upload-time = "2024-09-29T11:48:51.587Z" }, +] + [[package]] name = "pyglet" version = "1.4.11" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version < '3.14' and sys_platform == 'win32'", + "python_full_version >= '3.14' and sys_platform == 'emscripten'", + "python_full_version >= '3.14' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'win32'", + "python_full_version < '3.13' and sys_platform == 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'emscripten'", + "python_full_version < '3.13' and sys_platform == 'emscripten'", + "python_full_version == '3.13.*' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version < '3.13' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ - { name = "future", marker = "sys_platform == 'win32'" }, + { name = "future", marker = "sys_platform != 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/00/cd/e22352401f93f1f0ecc24d28f7b3f6896950c8cc4dacb5a8858e6aa65c19/pyglet-1.4.11.zip", hash = "sha256:e4cc8dc2f09d8487f7b3e2d93bd1961528afe989d058177b26a46d3508fd2c33", size = 7863507, upload-time = "2020-04-19T00:53:37.738Z" } wheels = [ @@ -1832,164 +2142,169 @@ wheels = [ [[package]] name = "pyglet" -version = "1.5.27" +version = "2.1.14" source = { registry = "https://pypi.org/simple" } resolution-markers = [ - "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.14' and sys_platform == 'emscripten'", - "python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version >= '3.14' and sys_platform == 'darwin'", + "python_full_version == '3.13.*' and sys_platform == 'darwin'", + "python_full_version < '3.13' and sys_platform == 'darwin'", ] -sdist = { url = "https://files.pythonhosted.org/packages/44/34/c11af4ae44bdd601e7d837add3d5c11451fe10f8f3d364f0b3ec19dd5f6b/pyglet-1.5.27.zip", hash = "sha256:4d00e067451f3b10fd51b69764fddab65444372a2da344ee2b35f0a8e6ebf005", size = 6978692, upload-time = "2022-09-21T11:17:18.163Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/a6/ffd78b2d05a820ced85baa11210b8e5d0db0d951767021150be0a231df00/pyglet-2.1.14.tar.gz", hash = "sha256:feb3fba05a85f50f793688d88ddfbcdc57044d971f2d8d2107eb7578eb4af51e", size = 6595146, upload-time = "2026-04-05T08:24:35.549Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/da/259b29659834f31f90b326b0f21466dc332eba9d5b89f6dbd849eabf9bc7/pyglet-1.5.27-py3-none-any.whl", hash = "sha256:7ce2eb5a299cda92fcc099f533520cdaa2f157a175d6c1442a2ae4d769284d2d", size = 1135252, upload-time = "2022-09-21T11:17:13.611Z" }, + { url = "https://files.pythonhosted.org/packages/ae/d4/789d34a4674a4ccc0b65ad54d0f963f873d39000c3ebed0880574d5437e5/pyglet-2.1.14-py3-none-any.whl", hash = "sha256:70febf03f206607103e1f9806527019c589002626937aecdca4d095ce0a4b9b0", size = 1032928, upload-time = "2026-04-05T08:24:29.068Z" }, ] [[package]] name = "pygments" -version = "2.19.2" +version = "2.20.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, ] +[[package]] +name = "pyo" +version = "1.0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/77/c8/e949d16170a9f448994be74963fad54557c13d1c4e4302590fa35280ae55/pyo-1.0.5.tar.gz", hash = "sha256:e042d947a0b641b400e228f9e21eeca21df8bf4895c6dbd013f87638d7728e31", size = 5249926, upload-time = "2023-03-26T13:47:38.382Z" } + [[package]] name = "pyobjc" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-accessibility", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-accounts", marker = "platform_release >= '12.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-addressbook", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-adservices", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-adsupport", marker = "platform_release >= '18.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-applescriptkit", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-applescriptobjc", marker = "platform_release >= '10.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-applicationservices", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-apptrackingtransparency", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-authenticationservices", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-automaticassessmentconfiguration", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-automator", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-avfoundation", marker = "platform_release >= '11.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-avkit", marker = "platform_release >= '13.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-businesschat", marker = "platform_release >= '18.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-calendarstore", marker = "platform_release >= '9.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-callkit", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cfnetwork", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-classkit", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cloudkit", marker = "platform_release >= '14.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-collaboration", marker = "platform_release >= '9.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-colorsync", marker = "platform_release >= '17.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-contacts", marker = "platform_release >= '15.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-contactsui", marker = "platform_release >= '15.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coreaudio", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coreaudiokit", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-corebluetooth", marker = "platform_release >= '14.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coredata", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-corehaptics", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-corelocation", marker = "platform_release >= '10.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coremedia", marker = "platform_release >= '11.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coremediaio", marker = "platform_release >= '11.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coremidi", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coreml", marker = "platform_release >= '17.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coremotion", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coreservices", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-corespotlight", marker = "platform_release >= '17.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coretext", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-corewlan", marker = "platform_release >= '10.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cryptotokenkit", marker = "platform_release >= '14.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-devicecheck", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-dictionaryservices", marker = "platform_release >= '9.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-discrecording", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-discrecordingui", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-diskarbitration", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-dvdplayback", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-eventkit", marker = "platform_release >= '12.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-exceptionhandling", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-executionpolicy", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-externalaccessory", marker = "platform_release >= '17.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-fileprovider", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-fileproviderui", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-findersync", marker = "platform_release >= '14.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-fsevents", marker = "platform_release >= '9.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-gamecenter", marker = "platform_release >= '12.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-gamecontroller", marker = "platform_release >= '13.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-gamekit", marker = "platform_release >= '12.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-gameplaykit", marker = "platform_release >= '15.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-imagecapturecore", marker = "platform_release >= '10.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-imserviceplugin", marker = "platform_release >= '11.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-inputmethodkit", marker = "platform_release >= '9.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-installerplugins", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-instantmessage", marker = "platform_release >= '9.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-intents", marker = "platform_release >= '16.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-iosurface", marker = "platform_release >= '10.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-ituneslibrary", marker = "platform_release >= '10.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-kernelmanagement", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-latentsemanticmapping", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-launchservices", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-libdispatch", marker = "platform_release >= '12.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-linkpresentation", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-localauthentication", marker = "platform_release >= '14.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-mapkit", marker = "platform_release >= '13.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-mediaaccessibility", marker = "platform_release >= '13.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-medialibrary", marker = "platform_release >= '13.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-mediaplayer", marker = "platform_release >= '16.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-mediatoolbox", marker = "platform_release >= '13.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-message", marker = "platform_release < '13.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-metal", marker = "platform_release >= '15.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-metalkit", marker = "platform_release >= '15.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-metalperformanceshaders", marker = "platform_release >= '17.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-metalperformanceshadersgraph", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-mlcompute", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-modelio", marker = "platform_release >= '15.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-multipeerconnectivity", marker = "platform_release >= '14.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-naturallanguage", marker = "platform_release >= '18.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-netfs", marker = "platform_release >= '10.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-network", marker = "platform_release >= '18.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-networkextension", marker = "platform_release >= '15.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-notificationcenter", marker = "platform_release >= '14.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-opendirectory", marker = "platform_release >= '10.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-osakit", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-oslog", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-passkit", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-pencilkit", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-photos", marker = "platform_release >= '15.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-photosui", marker = "platform_release >= '15.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-preferencepanes", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-pushkit", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quicklookthumbnailing", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-replaykit", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-safariservices", marker = "platform_release >= '15.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-scenekit", marker = "platform_release >= '11.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-screensaver", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-screentime", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-scriptingbridge", marker = "platform_release >= '9.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-searchkit", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-security", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-securityfoundation", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-securityinterface", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-servernotification", marker = "platform_release >= '10.0' and platform_release < '13.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-servicemanagement", marker = "platform_release >= '10.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-social", marker = "platform_release >= '12.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-soundanalysis", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-speech", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-spritekit", marker = "platform_release >= '13.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-storekit", marker = "platform_release >= '11.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-syncservices", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-systemconfiguration", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-systemextensions", marker = "platform_release >= '19.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-uniformtypeidentifiers", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-usernotifications", marker = "platform_release >= '18.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-usernotificationsui", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-videosubscriberaccount", marker = "platform_release >= '18.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-videotoolbox", marker = "platform_release >= '12.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-virtualization", marker = "platform_release >= '20.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-vision", marker = "platform_release >= '17.0' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-webkit", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-accessibility", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-accounts", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-addressbook", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-adservices", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-adsupport", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-applescriptkit", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-applescriptobjc", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-applicationservices", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-apptrackingtransparency", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-authenticationservices", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-automaticassessmentconfiguration", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-automator", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-avfoundation", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-avkit", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-businesschat", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-calendarstore", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-callkit", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cfnetwork", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-classkit", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cloudkit", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-collaboration", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-colorsync", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-contacts", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-contactsui", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreaudio", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreaudiokit", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corebluetooth", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coredata", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corehaptics", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corelocation", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremediaio", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremidi", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreml", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremotion", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreservices", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corespotlight", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coretext", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corewlan", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cryptotokenkit", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-devicecheck", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-dictionaryservices", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-discrecording", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-discrecordingui", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-diskarbitration", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-dvdplayback", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-eventkit", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-exceptionhandling", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-executionpolicy", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-externalaccessory", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-fileprovider", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-fileproviderui", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-findersync", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-fsevents", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-gamecenter", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-gamecontroller", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-gamekit", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-gameplaykit", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-imagecapturecore", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-imserviceplugin", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-inputmethodkit", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-installerplugins", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-instantmessage", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-intents", marker = "platform_release >= '16.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-iosurface", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-ituneslibrary", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-kernelmanagement", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-latentsemanticmapping", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-launchservices", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-libdispatch", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-linkpresentation", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-localauthentication", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-mapkit", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-mediaaccessibility", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-medialibrary", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-mediaplayer", marker = "platform_release >= '16.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-mediatoolbox", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-message", marker = "platform_release < '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metal", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metalkit", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metalperformanceshaders", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metalperformanceshadersgraph", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-mlcompute", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-modelio", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-multipeerconnectivity", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-naturallanguage", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-netfs", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-network", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-networkextension", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-notificationcenter", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-opendirectory", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-osakit", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-oslog", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-passkit", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-pencilkit", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-photos", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-photosui", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-preferencepanes", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-pushkit", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quicklookthumbnailing", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-replaykit", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-safariservices", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-scenekit", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-screensaver", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-screentime", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-scriptingbridge", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-searchkit", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-security", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-securityfoundation", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-securityinterface", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-servernotification", marker = "platform_release >= '10.0' and platform_release < '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-servicemanagement", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-social", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-soundanalysis", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-speech", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-spritekit", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-storekit", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-syncservices", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-systemconfiguration", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-systemextensions", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-uniformtypeidentifiers", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-usernotifications", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-usernotificationsui", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-videosubscriberaccount", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-videotoolbox", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-virtualization", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-vision", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-webkit", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/31/c7/d539edf73b3a75758ab905339343e2e89e002f13931994dbfe4585ef3775/pyobjc-7.3.tar.gz", hash = "sha256:322b07420f91b2dd7f624823e53046b922cab4aad28baab01a62463728b7e0c5", size = 7255, upload-time = "2021-06-07T08:59:30.045Z" } wheels = [ @@ -2007,9 +2322,9 @@ name = "pyobjc-framework-accessibility" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/86/eb/4f8e09db9da32c6e7b29da2bc66a2e8c1e1a17ec759bc32bbb6ec5a4217f/pyobjc-framework-Accessibility-7.3.tar.gz", hash = "sha256:75f11e49a5fdb871da7b86f2363aef9d4ce01975549b3ad70d67bdc53c94c365", size = 17106, upload-time = "2021-06-07T08:59:34.653Z" } wheels = [ @@ -2022,8 +2337,8 @@ name = "pyobjc-framework-accounts" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ee/a3/d18840eb405d135da5cde584be2fd9bd2c16ebf7855566c35f41b443d6dd/pyobjc-framework-Accounts-7.3.tar.gz", hash = "sha256:f35634b7f334a2ce11f8838af1045ec4bf0374000c9296a0f7bbf1b315d81afc", size = 13663, upload-time = "2021-06-07T08:59:35.512Z" } wheels = [ @@ -2035,8 +2350,8 @@ name = "pyobjc-framework-addressbook" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1f/ab/01cc2deeeabb16193b5ec0cf09f163efe6441c2a4df0c323acbda50c6e20/pyobjc-framework-AddressBook-7.3.tar.gz", hash = "sha256:2c5036369ee78b68337c6524b6a35060891f94d5ef24beacd8abb9c034f6f201", size = 61901, upload-time = "2021-06-07T08:59:38.126Z" } wheels = [ @@ -2049,8 +2364,8 @@ name = "pyobjc-framework-adservices" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4b/b1/b030e3e616794fcf5ce6bf1b1aafcf08022bf01081d818fad100f3fa7a4e/pyobjc-framework-AdServices-7.3.tar.gz", hash = "sha256:2506d71835258bf52605a8e1f93a1f33d6293c3fe864b3eaa020267860125188", size = 9366, upload-time = "2021-06-07T08:59:36.35Z" } wheels = [ @@ -2062,8 +2377,8 @@ name = "pyobjc-framework-adsupport" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ba/4d/f7c49acb29e72bc99a022bb84f225c26a3159a979798ba15a618be8a8cee/pyobjc-framework-AdSupport-7.3.tar.gz", hash = "sha256:c668c66d4ca0565279a2e8d0c496f63110be8dd6b7fc888438aebd7921e9c773", size = 10043, upload-time = "2021-06-07T08:59:37.179Z" } wheels = [ @@ -2075,8 +2390,8 @@ name = "pyobjc-framework-applescriptkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/00/ed/e28ec24c8ce129584f3573a9b65f1ca5e1a5182b0a6132067637085990b0/pyobjc-framework-AppleScriptKit-7.3.tar.gz", hash = "sha256:7c9adfc047222ce4c56dab7182b8408da48ec08c03a57463334f2a122a300aaf", size = 10287, upload-time = "2021-06-07T08:59:39.862Z" } wheels = [ @@ -2088,8 +2403,8 @@ name = "pyobjc-framework-applescriptobjc" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7f/65/3cbd675261453861817ef2c222ca5a2d6283d8c82d9bc7c64f3a4841b43f/pyobjc-framework-AppleScriptObjC-7.3.tar.gz", hash = "sha256:ac6dc66ae55c627182c3e873e58ed6ea1aecf4fc837ffc9321b7d70f9514c193", size = 10397, upload-time = "2021-06-07T08:59:40.709Z" } wheels = [ @@ -2101,9 +2416,9 @@ name = "pyobjc-framework-applicationservices" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ee/4c/dcec68f322e40177366807ec86ffb1a0ed8a26fc57befefa9455ebda4e20/pyobjc-framework-ApplicationServices-7.3.tar.gz", hash = "sha256:1925ac30a817e557d1c08450005103bbf76ebd3ff473631fe9875070377b0b4d", size = 105043, upload-time = "2021-06-07T08:59:41.609Z" } @@ -2112,8 +2427,8 @@ name = "pyobjc-framework-apptrackingtransparency" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/c9/a87df2995118547200e82d2f209db8873ee8eeff39e737c756e9566da635/pyobjc-framework-AppTrackingTransparency-7.3.tar.gz", hash = "sha256:e29f193ca3b302394d8d1305daf592fefca290e521d6b0150abb83a7e5ac059c", size = 10565, upload-time = "2021-06-07T08:59:39.026Z" } wheels = [ @@ -2125,8 +2440,8 @@ name = "pyobjc-framework-authenticationservices" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ce/21/5e5a8c3cc5d58b241c2ee47ca884eed7370e7cc8350ed5f0cea0f8f25a2b/pyobjc-framework-AuthenticationServices-7.3.tar.gz", hash = "sha256:610b2e02a6a9027e85bb7f0e232fbfb93348cff2ce3528e4c35bd4834c9ce164", size = 27716, upload-time = "2021-06-07T08:59:42.642Z" } wheels = [ @@ -2139,8 +2454,8 @@ name = "pyobjc-framework-automaticassessmentconfiguration" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/27/64/1872fa072c763e2c78cc5a9f47f6b29ee7c11d19b97de6ba0bbb860fc78e/pyobjc-framework-AutomaticAssessmentConfiguration-7.3.tar.gz", hash = "sha256:c932b31d3620c391e68a16afad85216cf9cc84e8efd938ff285563236890c09a", size = 18398, upload-time = "2021-06-07T08:59:43.669Z" } wheels = [ @@ -2153,8 +2468,8 @@ name = "pyobjc-framework-automator" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/72/0c/ac5ef18d7cd8cbcd0d6e3f80a20d25421d4019bf749fb0e65ec3f5d7910a/pyobjc-framework-Automator-7.3.tar.gz", hash = "sha256:37b9ba85dcb138fd2e6a0ff373e88dd33cab3a3137b11bf15dfb40c67f4934d0", size = 178939, upload-time = "2021-06-07T08:59:44.601Z" } wheels = [ @@ -2166,10 +2481,10 @@ name = "pyobjc-framework-avfoundation" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coremedia", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d1/5b/76c94cf8cc88e52e3237fe473db2615b77422e5b8d03420805b20755ba54/pyobjc-framework-AVFoundation-7.3.tar.gz", hash = "sha256:e187591b31c2b053d65aef8b8e3de3cd9ad53496b1ec9144e712dbfb2cded20b", size = 321145, upload-time = "2021-06-07T08:59:32.581Z" } wheels = [ @@ -2182,9 +2497,9 @@ name = "pyobjc-framework-avkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/49/52/48d10520665160db3ab4ffa32541e1fe7e63db443eb7234e7f4799dca0f0/pyobjc-framework-AVKit-7.3.tar.gz", hash = "sha256:00aa57ebe7068dccf53e571870bfffe8e9b0857f99f5225795dbe224b412d22f", size = 21618, upload-time = "2021-06-07T08:59:33.631Z" } wheels = [ @@ -2197,8 +2512,8 @@ name = "pyobjc-framework-businesschat" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/97/da/66f8d389790e30fd7e1517db6482611f845d6b85887b8d940daeec54c249/pyobjc-framework-BusinessChat-7.3.tar.gz", hash = "sha256:d1e3b16fe25deee3ba39fda17948d98c327523914eef7d16e30582f072442b79", size = 10187, upload-time = "2021-06-07T08:59:45.671Z" } wheels = [ @@ -2210,8 +2525,8 @@ name = "pyobjc-framework-calendarstore" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f7/ac/e2fa2d69a7184c26a40dfcce8023010dd20520f9f667ee80aa428039ec6b/pyobjc-framework-CalendarStore-7.3.tar.gz", hash = "sha256:fb19a8bb059fb84505ff427cea69df604ab4755ed3fee08278c7d94c34dc3cf2", size = 51989, upload-time = "2021-06-07T08:59:47.545Z" } wheels = [ @@ -2223,8 +2538,8 @@ name = "pyobjc-framework-callkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/68/71/89981da5216c8b0898a18d817fa13ff411c8f63789d06d6b7179355f9575/pyobjc-framework-CallKit-7.3.tar.gz", hash = "sha256:5167f17b90ac765774213826af6ce025864ea1643c27ff2f91c76201ada886c3", size = 16447, upload-time = "2021-06-07T08:59:48.707Z" } wheels = [ @@ -2236,8 +2551,8 @@ name = "pyobjc-framework-cfnetwork" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/56/4d/d54120d65bdc4a1b18ac99d599fe330558ccc99688be4285058bb63411cf/pyobjc-framework-CFNetwork-7.3.tar.gz", hash = "sha256:50f0041ee9803857a57827e1995794f8824a4bb7c685d736e1337853c64e741d", size = 46113, upload-time = "2021-06-07T08:59:46.571Z" } wheels = [ @@ -2250,8 +2565,8 @@ name = "pyobjc-framework-classkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/19/a9/6b1756c5b2488d0d1dbf64fdfc507c8e9cc037683004f265adc04bef8514/pyobjc-framework-ClassKit-7.3.tar.gz", hash = "sha256:7da8a38f9a939738092145c3455d1e8917b0e98e9140bdd5ac70dec87e7965c7", size = 21503, upload-time = "2021-06-07T08:59:49.615Z" } wheels = [ @@ -2264,11 +2579,11 @@ name = "pyobjc-framework-cloudkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-accounts", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coredata", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-corelocation", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-accounts", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coredata", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corelocation", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/44/35/73f1eb3c75adcd05e76945ad75f90e8034741750292a2fdda06b0061db30/pyobjc-framework-CloudKit-7.3.tar.gz", hash = "sha256:76efef08830d83c44bdaa9e20dfc652c065f2f8d6c7d1f10ee8dd29cba301869", size = 34058, upload-time = "2021-06-07T08:59:50.455Z" } wheels = [ @@ -2280,7 +2595,7 @@ name = "pyobjc-framework-cocoa" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/72/b8/ff4fad9271931746a38c0a253b26054d7a94720353d9ab8b9dd847f47e1f/pyobjc-framework-Cocoa-7.3.tar.gz", hash = "sha256:b18d05e7a795a3455ad191c3e43d6bfa673c2a4fd480bb1ccf57191051b80b7e", size = 3452011, upload-time = "2021-06-07T08:59:52.778Z" } @@ -2289,8 +2604,8 @@ name = "pyobjc-framework-collaboration" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bf/67/0dcef36d10d1ec6d4c8893092bcb73b85833200e21812aa4cdc267afac06/pyobjc-framework-Collaboration-7.3.tar.gz", hash = "sha256:43a1d85e5d418265f18a4c5d77f33eea6d7ad701482a7796f1986e0ef6f39d9d", size = 13282, upload-time = "2021-06-07T08:59:54.314Z" } wheels = [ @@ -2302,8 +2617,8 @@ name = "pyobjc-framework-colorsync" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b5/9e/4006df20c17d2d4b8c3353fa4b5812b92e764920ad2ed0a0d258b4f115ea/pyobjc-framework-ColorSync-7.3.tar.gz", hash = "sha256:7f95964f1290739642da32a40a6668e5b32d1477635435f3b6eb86689751c80f", size = 19183, upload-time = "2021-06-07T08:59:55.278Z" } wheels = [ @@ -2315,8 +2630,8 @@ name = "pyobjc-framework-contacts" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f9/2b/84d2deb3a9f767c865259ef035efb1bcbacaf9d9d7ed5e16b3f77d88c47b/pyobjc-framework-Contacts-7.3.tar.gz", hash = "sha256:912fccc3b44b9d3b53043df433729344a71ff7652bf18d22c8da4d41c11e444e", size = 39399, upload-time = "2021-06-07T08:59:56.345Z" } wheels = [ @@ -2329,9 +2644,9 @@ name = "pyobjc-framework-contactsui" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-contacts", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-contacts", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6c/62/2879507b5028e50d8e6c11319aac428e39d9f5d2536dc261306aca489742/pyobjc-framework-ContactsUI-7.3.tar.gz", hash = "sha256:c35b9f10395ef822bcb418541cca4d972fd4f54d064d29b247702e5deee77f0c", size = 16938, upload-time = "2021-06-07T08:59:57.244Z" } wheels = [ @@ -2344,8 +2659,8 @@ name = "pyobjc-framework-coreaudio" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/2f/b7a882ad9c937ba1219c2403b5c60084bea9aee3bd95b8b4fc9b38c5bb9d/pyobjc-framework-CoreAudio-7.3.tar.gz", hash = "sha256:37d161dc459ba309fa5f46655662cd63ff850b5edddde463c58594bdf4b4dee4", size = 83845, upload-time = "2021-06-07T08:59:58.398Z" } @@ -2354,9 +2669,9 @@ name = "pyobjc-framework-coreaudiokit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coreaudio", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreaudio", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0c/29/e3a476055c4b5afb4ed2d72636a56c686325a812ac2e570fccb72b19cc56/pyobjc-framework-CoreAudioKit-7.3.tar.gz", hash = "sha256:9f0ad55dedbff8539c89990a74bb57c452273ac32a5676acbc22becae677b683", size = 18554, upload-time = "2021-06-07T08:59:59.335Z" } wheels = [ @@ -2369,8 +2684,8 @@ name = "pyobjc-framework-corebluetooth" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/21/20/12eba7a7cdd7d3889b412c214a23a09273404dcb532bcffa0731c98ca330/pyobjc-framework-CoreBluetooth-7.3.tar.gz", hash = "sha256:86537978052481023cd378714c5e01a337794435aa1981db60c75517f7dc7fca", size = 33210, upload-time = "2021-06-07T09:00:00.222Z" } wheels = [ @@ -2383,8 +2698,8 @@ name = "pyobjc-framework-coredata" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/24/c5/9220628bcd3b3fc83553bb439b7afaa3a9eab527eee90c2e300f2d4dc97a/pyobjc-framework-CoreData-7.3.tar.gz", hash = "sha256:e7bb263a38ab0acfb931d8a116bde6d928a17a284d1ffa78eebb2d87f62da9b5", size = 144096, upload-time = "2021-06-07T09:00:01.214Z" } wheels = [ @@ -2397,8 +2712,8 @@ name = "pyobjc-framework-corehaptics" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e9/63/95536a2406284efcd3a2f7888de1285356ec5372994a84cf7daa990c2e0e/pyobjc-framework-CoreHaptics-7.3.tar.gz", hash = "sha256:e0ff9800e2ffe93c42583bb4f9cb29ebddd6c36f8c93aa12d5ffcf3ad942d788", size = 19019, upload-time = "2021-06-07T09:00:02.462Z" } wheels = [ @@ -2410,8 +2725,8 @@ name = "pyobjc-framework-corelocation" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/be/78/bbdc1538715008778aab07f2dd04bc5851310d0a46cef0935c4a3f6a0094/pyobjc-framework-CoreLocation-7.3.tar.gz", hash = "sha256:30060bf97e6cd858192e3cf6ad2725496838062b1750392d6f3c227a8b39bdf8", size = 51045, upload-time = "2021-06-07T09:00:03.379Z" } wheels = [ @@ -2424,8 +2739,8 @@ name = "pyobjc-framework-coremedia" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0b/5e/439807bb1de8288b34282290bc21b235be9c43622550bc2d8a6614ade5aa/pyobjc-framework-CoreMedia-7.3.tar.gz", hash = "sha256:c95a09979709241e50a2b000f6772751fed99850f1aaa2cacafd039f3a6b3e99", size = 84886, upload-time = "2021-06-07T09:00:06.483Z" } @@ -2434,8 +2749,8 @@ name = "pyobjc-framework-coremediaio" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/33/a9/c63ea865458a056beccf51cc1567bb3b5191d8ca677f9e4dccc517a43ee1/pyobjc-framework-CoreMediaIO-7.3.tar.gz", hash = "sha256:4d2b6106456219d8e74a0dcd9fd4ed1c9be50220b559a266f1048bfe0250a5df", size = 50249, upload-time = "2021-06-07T09:00:07.474Z" } wheels = [ @@ -2448,8 +2763,8 @@ name = "pyobjc-framework-coremidi" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e4/4d/6565815121733f0b9af19308d5f2f3ed2c9cfe23ce52340bb49254ffede8/pyobjc-framework-CoreMIDI-7.3.tar.gz", hash = "sha256:6e333eeddb136579128c8e61476eb638d1db5b7a3bcf2f79ac6f32b00c39ad16", size = 30792, upload-time = "2021-06-07T09:00:04.284Z" } wheels = [ @@ -2462,8 +2777,8 @@ name = "pyobjc-framework-coreml" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9d/9c/798cd18397330159a9ef140a109a46dbb80c4486937cd76341ad345222d0/pyobjc-framework-CoreML-7.3.tar.gz", hash = "sha256:dd6810f920e4b6aba14d3e9a471ea3e6cd36b315e324b76a92c46d7ca8ef7700", size = 33143, upload-time = "2021-06-07T09:00:05.375Z" } wheels = [ @@ -2476,8 +2791,8 @@ name = "pyobjc-framework-coremotion" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7d/c9/fb47b29e42978c4aacea2ab18415d91b22ee156e95e0b79a3c18e8dfb04e/pyobjc-framework-CoreMotion-7.3.tar.gz", hash = "sha256:4338c0f24d99d6dac0555a4df1a9265da5164e8603af37eb8345a7e1785624e3", size = 19407, upload-time = "2021-06-07T09:00:08.441Z" } wheels = [ @@ -2489,8 +2804,8 @@ name = "pyobjc-framework-coreservices" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-fsevents", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-fsevents", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ee/7f/9af202b65550e0e00d2e487a60abe6d9a56cbc35079e2162b358b1c1a1ce/pyobjc-framework-CoreServices-7.3.tar.gz", hash = "sha256:68240e0314e144e8cccef52c5db112bc4098cb0841c36e747b2f35eeee739e96", size = 484439, upload-time = "2021-06-07T09:00:09.514Z" } wheels = [ @@ -2503,8 +2818,8 @@ name = "pyobjc-framework-corespotlight" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/43/d4/1a3c3a8f43a81c2b196203e9dfecfc47a3cd8592b09dac964aa8f44fc746/pyobjc-framework-CoreSpotlight-7.3.tar.gz", hash = "sha256:5cb0f25f3c48753a355e1f90c7bd94ea5549d03fa33edf92053fb69d8cb0a9de", size = 25707, upload-time = "2021-06-07T09:00:10.598Z" } wheels = [ @@ -2517,9 +2832,9 @@ name = "pyobjc-framework-coretext" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1f/5d/4651dd8f358cc40cbdc8669c785d865c2240e5afc7eadb21571a81561c8b/pyobjc-framework-CoreText-7.3.tar.gz", hash = "sha256:5b5fc91bcbd2fe5199f6b65971d62bea02f942c76d6acb59168c041c7af435d9", size = 120662, upload-time = "2021-06-07T09:00:11.524Z" } @@ -2528,8 +2843,8 @@ name = "pyobjc-framework-corewlan" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/88/0b/b04deaf1605724167ccd4cf25269857c1b000fa0edc7beeaf6f889a8bee8/pyobjc-framework-CoreWLAN-7.3.tar.gz", hash = "sha256:63ab61cd28cd1d61619150e1eff85e3c953f28b4240ec4011229100bb4749657", size = 38995, upload-time = "2021-06-07T09:00:13.497Z" } wheels = [ @@ -2542,8 +2857,8 @@ name = "pyobjc-framework-cryptotokenkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7c/44/8b27be7d8c7983d645e9a92354cbe72840abc9109e4ad5a29172459d4e3d/pyobjc-framework-CryptoTokenKit-7.3.tar.gz", hash = "sha256:904ea3ee27135a2fa4b139ed8aed0a50f0c2ce7d3633c7e1e79d317aa5c4e9f8", size = 30365, upload-time = "2021-06-07T09:00:14.438Z" } wheels = [ @@ -2556,8 +2871,8 @@ name = "pyobjc-framework-devicecheck" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/13/dc/a6a75f82c5111a090f3d576af98f597e344b97ce9d3ff3f8da4694481aea/pyobjc-framework-DeviceCheck-7.3.tar.gz", hash = "sha256:9f65aa882367a367d8f05bbed52ad822f883970bc0afd7ae0bfb9941e16f13bc", size = 11083, upload-time = "2021-06-07T09:00:16.342Z" } wheels = [ @@ -2569,8 +2884,8 @@ name = "pyobjc-framework-dictionaryservices" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coreservices", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreservices", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/12/25/6318e25fab6feda181b54c3b7641c4ffe7f77960959af1c99cc78c96964d/pyobjc-framework-DictionaryServices-7.3.tar.gz", hash = "sha256:3187b7c24f3fb8e6f5aea89eefacf3657a4bd4fa0f589a69836fb5aeafe2733b", size = 9016, upload-time = "2021-06-07T09:00:17.222Z" } wheels = [ @@ -2582,8 +2897,8 @@ name = "pyobjc-framework-discrecording" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/30/18/831e6010144dc196fffcc2d013bca88d95d77997c5961de1befc3ad5faf3/pyobjc-framework-DiscRecording-7.3.tar.gz", hash = "sha256:9a1dc83f44227e1522643ec3c0fa774dee9e42b501fce7e1e39ba1e4907e1e22", size = 62844, upload-time = "2021-06-07T09:00:18.185Z" } wheels = [ @@ -2596,9 +2911,9 @@ name = "pyobjc-framework-discrecordingui" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-discrecording", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-discrecording", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f1/cf/f65b8593edd500ec9cdd0ec2381bf8712cd019d9cae1eaff0d4b0693704e/pyobjc-framework-DiscRecordingUI-7.3.tar.gz", hash = "sha256:5db083a92bc9513a818d1bc4574a3313f9b967f2aa8dce888ebe436b9a948673", size = 14851, upload-time = "2021-06-07T09:00:19.24Z" } wheels = [ @@ -2610,8 +2925,8 @@ name = "pyobjc-framework-diskarbitration" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/87/cb/d7ce7657e13281f101322974cc9d12180d9e8a6d72c4bf8b1766df6386fa/pyobjc-framework-DiskArbitration-7.3.tar.gz", hash = "sha256:f34d28226760fdce865487b2ea6835e5256f0df00deb68154515e51dc36ea352", size = 15737, upload-time = "2021-06-07T09:00:20.094Z" } wheels = [ @@ -2623,8 +2938,8 @@ name = "pyobjc-framework-dvdplayback" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/10/bc/56b3cdaf4363d5228261fcda026201fbbc14a42116478add5cbf3995ec9e/pyobjc-framework-DVDPlayback-7.3.tar.gz", hash = "sha256:4e71fafed5901652ad7540f1f25e9250c5c6522039bf74681e850c6241bfe497", size = 29993, upload-time = "2021-06-07T09:00:15.397Z" } wheels = [ @@ -2636,8 +2951,8 @@ name = "pyobjc-framework-eventkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ea/7a/fe175d965aea89d8c10ec7d30017ee9cc0d8d80cea92648e58b4b1af2ad0/pyobjc-framework-EventKit-7.3.tar.gz", hash = "sha256:826e04c0211c781ce85b4efb0de4b72d833a66e8475e3f1728f318253fd9ffea", size = 31109, upload-time = "2021-06-07T09:00:20.997Z" } wheels = [ @@ -2649,8 +2964,8 @@ name = "pyobjc-framework-exceptionhandling" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2a/76/45a87c14d47b93d4640f330e3466c19b46706d31f0c454247a3305343709/pyobjc-framework-ExceptionHandling-7.3.tar.gz", hash = "sha256:1843f8e48d88c8518280c0daf23247a4f12897cb3b7b9b77ee014cf0b4a145bd", size = 15565, upload-time = "2021-06-07T09:00:23.149Z" } wheels = [ @@ -2662,8 +2977,8 @@ name = "pyobjc-framework-executionpolicy" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/24/c4/7eca7181bb0ce62dfcff075cf2519c3e13adbc00236ddcab7daa8b999050/pyobjc-framework-ExecutionPolicy-7.3.tar.gz", hash = "sha256:27f1bd941320238eaebf933b30b401cf0af5b581af2d4197554ef6977125a2ef", size = 10920, upload-time = "2021-06-07T09:00:24.055Z" } wheels = [ @@ -2675,8 +2990,8 @@ name = "pyobjc-framework-externalaccessory" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/da/c0/d63b51fd9f0445529a4d4fc67593c28a2f494f0065f63ee5a581f0938623/pyobjc-framework-ExternalAccessory-7.3.tar.gz", hash = "sha256:74b5c2cce8f2a7a70c2e57e6ecf773ac5e083887e27b5acb86e97eb5c4f1d472", size = 19003, upload-time = "2021-06-07T09:00:24.932Z" } wheels = [ @@ -2689,8 +3004,8 @@ name = "pyobjc-framework-fileprovider" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/f2/588a1c77e69e8775940b6450444b262fc8e92e666abd5db219e4dbaa8adc/pyobjc-framework-FileProvider-7.3.tar.gz", hash = "sha256:cec94c9e2eef09e624834a358da7c0827938eb0825c2804b09a2bf20858a6615", size = 28369, upload-time = "2021-06-07T09:00:26.966Z" } @@ -2699,8 +3014,8 @@ name = "pyobjc-framework-fileproviderui" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-fileprovider", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-fileprovider", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/07/20/20c2a6a9ad0e12f64be6f7d31aaa2148a9618157c55ad8ca9a36f256a9d4/pyobjc-framework-FileProviderUI-7.3.tar.gz", hash = "sha256:2cf6f7182bde330ee018233014549f24ed89002f543364f55ca99fd5ee51051e", size = 10732, upload-time = "2021-06-07T09:00:28.01Z" } wheels = [ @@ -2712,8 +3027,8 @@ name = "pyobjc-framework-findersync" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f6/d8/c648c33dab1f530938019c4ea3e84783dd2f4bd2cb2aac957231f89dafd7/pyobjc-framework-FinderSync-7.3.tar.gz", hash = "sha256:f68c6920a1a8445c170dfc6c345243e772e331ff01f5a2eef04b330ab5ae8c42", size = 11878, upload-time = "2021-06-07T09:00:28.985Z" } wheels = [ @@ -2725,8 +3040,8 @@ name = "pyobjc-framework-fsevents" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/32/8a2be676512270a6875aa0e8241f544d16e2b366d32f43a8039a3f54e2fa/pyobjc-framework-FSEvents-7.3.tar.gz", hash = "sha256:3d12df35cc0b18c3f7c677d6bc870a7ea13a5d1c2f16456c1f445e0b894ddb55", size = 24494, upload-time = "2021-06-07T09:00:25.897Z" } wheels = [ @@ -2739,8 +3054,8 @@ name = "pyobjc-framework-gamecenter" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2b/ee/90942dd611223bea0b18d37e4247095f6c9514f3744016256e6f8d87a61c/pyobjc-framework-GameCenter-7.3.tar.gz", hash = "sha256:1a13c35fa7f109d043e5d0d8cd5f808d061a4ce525580550dceca2697270beaf", size = 29725, upload-time = "2021-06-07T09:00:29.898Z" } wheels = [ @@ -2753,8 +3068,8 @@ name = "pyobjc-framework-gamecontroller" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9a/89/0fe15420fc35f61329a7d85a17ed07b536f496597eae1dfb2b8b4105236b/pyobjc-framework-GameController-7.3.tar.gz", hash = "sha256:745088df9c3d127e0949f5ee19d12c8c88f305c8406769f12da4299338320d91", size = 37156, upload-time = "2021-06-07T09:00:30.936Z" } wheels = [ @@ -2767,9 +3082,9 @@ name = "pyobjc-framework-gamekit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c8/9c/c259af776659560b3941313a1743ffeef3a5eb265eb30d23c73079797f46/pyobjc-framework-GameKit-7.3.tar.gz", hash = "sha256:6bb7b60b638026c2c5dca0f2ed92e0710e83d7b2ac5393387cbe3b80f1f46c6b", size = 62018, upload-time = "2021-06-07T09:00:31.963Z" } wheels = [ @@ -2782,9 +3097,9 @@ name = "pyobjc-framework-gameplaykit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-spritekit", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-spritekit", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0c/8d/a972fc300a4ace1ecae65546339006b5e8dd079c2d4a7b7d820d90de7659/pyobjc-framework-GameplayKit-7.3.tar.gz", hash = "sha256:6138e5e7eb16c0f6dc1d9d9d570589f6dd19746be7a5a84ef69f3288e8f87cbb", size = 36561, upload-time = "2021-06-07T09:00:32.962Z" } wheels = [ @@ -2797,8 +3112,8 @@ name = "pyobjc-framework-imagecapturecore" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c2/e8/d0b5514bab4ced0dbd4b4064fd743ed23256fd146e82769908709809110f/pyobjc-framework-ImageCaptureCore-7.3.tar.gz", hash = "sha256:e0143ae9d33d5dae5427b1823444a83f89fbdbcc5f0d42b3c3fe5e6dd17ec4e5", size = 48277, upload-time = "2021-06-07T09:00:35.748Z" } wheels = [ @@ -2811,8 +3126,8 @@ name = "pyobjc-framework-imserviceplugin" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/21/87/24018038b97447d76d8d58930023cf7c752dcc4134c7843952045d3ad555/pyobjc-framework-IMServicePlugIn-7.3.tar.gz", hash = "sha256:04faa56cdf2899bba8d7d397d9cd77a8bf12aa631d979b005365201611a0712f", size = 21039, upload-time = "2021-06-07T09:00:33.883Z" } wheels = [ @@ -2825,8 +3140,8 @@ name = "pyobjc-framework-inputmethodkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a0/df/807b7248bd4502f22a2fd2e2cb489ee1a68fb1c691c217483d2414e05dcc/pyobjc-framework-InputMethodKit-7.3.tar.gz", hash = "sha256:c96d51bdbdf55c05ca53ed50691c9e7258265c700126f25498f293d708dbb601", size = 22661, upload-time = "2021-06-07T09:00:36.849Z" } wheels = [ @@ -2839,8 +3154,8 @@ name = "pyobjc-framework-installerplugins" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c9/21/f38c01a77dadf395ddd02006164e7f5c0c23e75aef5d921c4c5fa77b6213/pyobjc-framework-InstallerPlugins-7.3.tar.gz", hash = "sha256:d1bd6b8df714a6f7dd7dc19e5a96c13434732ff6a17dcc3bb21f88ea7cd9cdf2", size = 23873, upload-time = "2021-06-07T09:00:37.878Z" } wheels = [ @@ -2852,9 +3167,9 @@ name = "pyobjc-framework-instantmessage" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b7/60/82f3a3fd9c221523a9df7bda2826be49e46338c517f954d87859b6017096/pyobjc-framework-InstantMessage-7.3.tar.gz", hash = "sha256:dbc907cbdd4ae0766f568c709460381846fb57852496177dafb323960e52f22f", size = 30201, upload-time = "2021-06-07T09:00:38.861Z" } wheels = [ @@ -2866,8 +3181,8 @@ name = "pyobjc-framework-intents" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d3/9d/75e5eb299e0cb970fa032f8b45d6c947cfce6bea58ea879b0f8f4934f1d9/pyobjc-framework-Intents-7.3.tar.gz", hash = "sha256:1220eeaad2849f7ba75f947c94343087f33495b678bf3bdb695a22ba23520a4d", size = 107393, upload-time = "2021-06-07T09:00:40.036Z" } wheels = [ @@ -2880,8 +3195,8 @@ name = "pyobjc-framework-iosurface" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5e/67/2393d1e833f31ec3a1c9e38bce80968e60fd7d544d3be0144b34b9aa7b2a/pyobjc-framework-IOSurface-7.3.tar.gz", hash = "sha256:bbaa566eb2972cfd44531875aefb7c0622f31743b4d85bd957348edc7eab21d5", size = 15198, upload-time = "2021-06-07T09:00:34.793Z" } wheels = [ @@ -2893,8 +3208,8 @@ name = "pyobjc-framework-ituneslibrary" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/87/f6/e0b3627422a871cdadc4a0351def7a1bc8896058edb8cb94f783fa7ae595/pyobjc-framework-iTunesLibrary-7.3.tar.gz", hash = "sha256:340c5aa952871aa34a7dcad677fb537252d4ecedde499d88f89de0093b117ac3", size = 18093, upload-time = "2021-06-07T09:01:49.046Z" } wheels = [ @@ -2906,8 +3221,8 @@ name = "pyobjc-framework-kernelmanagement" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1d/62/4689d17249394faa671b0f3e7349c76ba8307be5c3272ad19773e26aaf81/pyobjc-framework-KernelManagement-7.3.tar.gz", hash = "sha256:7f04f73ec4dbaab3402f5c45b716ce35d34a595f9cf87bcb62573ee9beb2a00b", size = 10285, upload-time = "2021-06-07T09:00:42.08Z" } wheels = [ @@ -2919,8 +3234,8 @@ name = "pyobjc-framework-latentsemanticmapping" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/c5/490e3a4305f51d229ba64c65382f979354cb08a8460d4db842e38daa35ec/pyobjc-framework-LatentSemanticMapping-7.3.tar.gz", hash = "sha256:67abdb884a5114887d10c7528711eef9501843c14188a150c915339d796defd0", size = 14493, upload-time = "2021-06-07T09:00:43.477Z" } wheels = [ @@ -2932,8 +3247,8 @@ name = "pyobjc-framework-launchservices" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coreservices", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreservices", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/03/ce/7c7f4211348272b572bb900e9a589ec21051420c934cfb78e87b3e909b01/pyobjc-framework-LaunchServices-7.3.tar.gz", hash = "sha256:53cdb7c7566b169c6c373512b8e5a6b3ad8cdf540ad56eb36c9a424e5228fb1b", size = 18856, upload-time = "2021-06-07T09:00:44.433Z" } wheels = [ @@ -2945,7 +3260,7 @@ name = "pyobjc-framework-libdispatch" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/81/d0/592dac0b9104494d414b831f83833a07214c5a6d24cb9f01b697e6797860/pyobjc-framework-libdispatch-7.3.tar.gz", hash = "sha256:c3e63ce294e50a36c17bc9e65ccf3e448995931fc10fc0c15f899d27c438e25f", size = 27013, upload-time = "2021-06-07T09:01:49.971Z" } @@ -2954,9 +3269,9 @@ name = "pyobjc-framework-linkpresentation" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7b/87/f69d7af3c03b25379cf67368d551a11c9e7770a47680775998160f78486a/pyobjc-framework-LinkPresentation-7.3.tar.gz", hash = "sha256:ba06355eedbbd83b703171d53d7cda2ff2294c4eb8ececd431a10683bf09bdbe", size = 11510, upload-time = "2021-06-07T09:00:45.311Z" } wheels = [ @@ -2968,9 +3283,9 @@ name = "pyobjc-framework-localauthentication" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-security", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-security", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0e/d3/e55fb2d11f88e9445f825298765a7c72d2145412935573c91b191dbc8dfd/pyobjc-framework-LocalAuthentication-7.3.tar.gz", hash = "sha256:0c7ac94f90e3e5e1797980dca08548f5e7ce38ba1578d10b45dd2b611c41183a", size = 14293, upload-time = "2021-06-07T09:00:46.205Z" } wheels = [ @@ -2982,10 +3297,10 @@ name = "pyobjc-framework-mapkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-corelocation", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corelocation", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/63/3a/502e76dfbb58d146cde2c2f295c5018f1cbfad6436a3937c5c3b00078b0d/pyobjc-framework-MapKit-7.3.tar.gz", hash = "sha256:efb836c7a9e97c971cec4549043bfdbf4088164f75b177ac3de67a3a98817d2f", size = 63016, upload-time = "2021-06-07T09:00:48.232Z" } wheels = [ @@ -2998,8 +3313,8 @@ name = "pyobjc-framework-mediaaccessibility" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c9/d7/82778e4f77b220fa3d7d1fb299d3bcaa26a8f07505ac5140dd4ed2c3f119/pyobjc-framework-MediaAccessibility-7.3.tar.gz", hash = "sha256:687403801f89805710c8de0a3a41811614e772776f19c9e041c06eb4fb529c24", size = 12945, upload-time = "2021-06-07T09:00:49.132Z" } wheels = [ @@ -3011,9 +3326,9 @@ name = "pyobjc-framework-medialibrary" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0d/99/cd82e857ee6ba00bcda83fcde82467560df314ad4164614a70e2905633bd/pyobjc-framework-MediaLibrary-7.3.tar.gz", hash = "sha256:d23b9f80ca63cd8e2471e64794df30231e1b71eb9f0259c986225b1a58face22", size = 14697, upload-time = "2021-06-07T09:00:50.016Z" } wheels = [ @@ -3025,8 +3340,8 @@ name = "pyobjc-framework-mediaplayer" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-avfoundation", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-avfoundation", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/27/ee/a791c1369997b8ee77212a50e14443bf7383c26c59582dd13261619bfbbb/pyobjc-framework-MediaPlayer-7.3.tar.gz", hash = "sha256:76e3746cad7c1f0fa2f08ae3ba922316c634fc85c4c7616b573e79bd781c30be", size = 27972, upload-time = "2021-06-07T09:00:50.869Z" } wheels = [ @@ -3038,8 +3353,8 @@ name = "pyobjc-framework-mediatoolbox" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e9/fd/dc5bc7eba03433633931874b032ea799afbb0a810f567d16514a76acf1bc/pyobjc-framework-MediaToolbox-7.3.tar.gz", hash = "sha256:52013a09fc7d1cab5613d2044f14016f7b6b504c5ed50cca80894f93de59008e", size = 20656, upload-time = "2021-06-07T09:00:51.911Z" } wheels = [ @@ -3052,8 +3367,8 @@ name = "pyobjc-framework-message" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b6/64/ad2d795240fe63cd8f49c94934f8c7d50a4751b225216730e0499f1318af/pyobjc-framework-Message-7.3.tar.gz", hash = "sha256:3a713a19357ebe26b6476489d5ff0c6ef3d9c477c40595d13d218dcf6ea9cc38", size = 10427, upload-time = "2021-06-07T09:00:52.894Z" } wheels = [ @@ -3065,8 +3380,8 @@ name = "pyobjc-framework-metal" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/91/84/f160ca40f3b67961dc81ff141fe20ea98af3c10567c6795aabebb0bc461e/pyobjc-framework-Metal-7.3.tar.gz", hash = "sha256:249d996476cee9e8762839b16d6fcfedd4acd3195fe1ef436aa6e3806177db37", size = 100129, upload-time = "2021-06-07T09:00:54.124Z" } wheels = [ @@ -3079,9 +3394,9 @@ name = "pyobjc-framework-metalkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-metal", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metal", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2f/fe/bf1db65ad098f279a0777ead815ce0c0c2534e46eef0464dd4844394155b/pyobjc-framework-MetalKit-7.3.tar.gz", hash = "sha256:a834a881fef2f4986384423a3393ebd934719ca436e2e9df76519ef424162278", size = 23236, upload-time = "2021-06-07T09:00:55.612Z" } wheels = [ @@ -3094,8 +3409,8 @@ name = "pyobjc-framework-metalperformanceshaders" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-metal", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metal", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fd/95/58d5259282f2517cb22944f5af5df8ca2234aa80d6c0f5966a85b469aa9b/pyobjc-framework-MetalPerformanceShaders-7.3.tar.gz", hash = "sha256:aab31f039b4236a7799cf36ea9343c04065856f0257b874e8bfd653d35069007", size = 80524, upload-time = "2021-06-07T09:00:56.548Z" } wheels = [ @@ -3108,8 +3423,8 @@ name = "pyobjc-framework-metalperformanceshadersgraph" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-metalperformanceshaders", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metalperformanceshaders", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c4/47/34f55bb8d9ff2ab7ee277d4c1e248208a6805666a677839586f1fa719d08/pyobjc-framework-MetalPerformanceShadersGraph-7.3.tar.gz", hash = "sha256:a81d957f0cfb7901ef6698d892df1432bd9d84bc2ef814319e91faf0663e0586", size = 15473, upload-time = "2021-06-07T09:00:58.467Z" } wheels = [ @@ -3121,8 +3436,8 @@ name = "pyobjc-framework-mlcompute" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0f/a8/1945ebefec1bd56ca14d877eb24b9b88fd907d929889dcb56e7d21a76b05/pyobjc-framework-MLCompute-7.3.tar.gz", hash = "sha256:113c78b4decb48e6c46a8e8037476b26869a7ac4439ed7e83e5a92224ee39beb", size = 26463, upload-time = "2021-06-07T09:00:47.211Z" } wheels = [ @@ -3134,9 +3449,9 @@ name = "pyobjc-framework-modelio" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/c4/9eff9a2ec52d15677e9c2de16455fe047df7066dbec7fc324466fbef01b1/pyobjc-framework-ModelIO-7.3.tar.gz", hash = "sha256:d151e5888300d533e23939df79be04563925fe9620d2698173b5e05b9e721678", size = 59012, upload-time = "2021-06-07T09:00:59.387Z" } wheels = [ @@ -3149,8 +3464,8 @@ name = "pyobjc-framework-multipeerconnectivity" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/70/5b/2bdce534fc3ca809bdc4e1f76428c229949684ce4bdaa7455a022fd297a8/pyobjc-framework-MultipeerConnectivity-7.3.tar.gz", hash = "sha256:a5b42dede182ad3e42d0e5bc764d55d3b75741383508f88c914d9559b8a6cfae", size = 21038, upload-time = "2021-06-07T09:01:00.313Z" } wheels = [ @@ -3163,8 +3478,8 @@ name = "pyobjc-framework-naturallanguage" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cb/30/269fc73ebd22ec87db9adf73f07411db3a7fda5726f3e39cc732f230dc55/pyobjc-framework-NaturalLanguage-7.3.tar.gz", hash = "sha256:b48390651b857f6ed3fb3eeeb843f77cac033c32ad2bc367d4aeed17b63b1527", size = 20565, upload-time = "2021-06-07T09:01:01.352Z" } wheels = [ @@ -3176,8 +3491,8 @@ name = "pyobjc-framework-netfs" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f0/ca/03f4236b540c517b86d695383eea73b10d259a5283009f13f83e9986a059/pyobjc-framework-NetFS-7.3.tar.gz", hash = "sha256:a5f6fb8ab739c9466ba9a81e3a742f92a8808e6716385aa15078630110f2ca6f", size = 13100, upload-time = "2021-06-07T09:01:02.326Z" } wheels = [ @@ -3189,8 +3504,8 @@ name = "pyobjc-framework-network" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/99/cf/4fd0b4f614b14e905578ebfdb5d87b1cdfc4be79c7d63b55df452a9bc8ff/pyobjc-framework-Network-7.3.tar.gz", hash = "sha256:c40fe885fcfc9e35680d81eb5a3b0bfc07e51b68039e928884da770bb0e45a78", size = 48465, upload-time = "2021-06-07T09:01:03.247Z" } wheels = [ @@ -3203,8 +3518,8 @@ name = "pyobjc-framework-networkextension" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/08/ce/b1eca2483773e79e0c1cf6424e6cb1dc2db748a45ecffc95c6d4e9c0d227/pyobjc-framework-NetworkExtension-7.3.tar.gz", hash = "sha256:0bd2422628be9848297aa58c3b53af2da5c4dac8022d55684dae37e0264bfcf7", size = 51669, upload-time = "2021-06-07T09:01:04.153Z" } wheels = [ @@ -3217,8 +3532,8 @@ name = "pyobjc-framework-notificationcenter" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bd/04/733ef60c25ac84aa472a7adf8c85851be2d2547b81a23f7cb05eaa290869/pyobjc-framework-NotificationCenter-7.3.tar.gz", hash = "sha256:64866915bf4c20429fe27c2ab5ab86cab74fa0e557b24382c77a6a6d3d8878ea", size = 19577, upload-time = "2021-06-07T09:01:05.078Z" } wheels = [ @@ -3231,8 +3546,8 @@ name = "pyobjc-framework-opendirectory" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e3/1d/1c5ca2cb8b2477e9e819251df16a7a8b57ca01494cce93f6df1c65be6bc4/pyobjc-framework-OpenDirectory-7.3.tar.gz", hash = "sha256:2e60807e4385a0c781f4535af733a0ff38fc2c4fd29cb0622c0829b0e4ae34ac", size = 100524, upload-time = "2021-06-07T09:01:08.051Z" } wheels = [ @@ -3244,8 +3559,8 @@ name = "pyobjc-framework-osakit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f9/d7/c33d1323b655bdfc33428b2f33cf27dd3b3655dd45147a76baf4b6bec074/pyobjc-framework-OSAKit-7.3.tar.gz", hash = "sha256:eff377c2c5c8f498ee4522aff406dac17381fe88bf93bad474ba92f77cff6082", size = 13942, upload-time = "2021-06-07T09:01:06.174Z" } wheels = [ @@ -3257,10 +3572,10 @@ name = "pyobjc-framework-oslog" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coremedia", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/49/a2/734e63e0621e577235a69cfabdf0441b3a70d7a84365980a3db325fab940/pyobjc-framework-OSLog-7.3.tar.gz", hash = "sha256:251afa4a571f03a73b48807e95972eda9016746c08d55dcffad72454db485f86", size = 19423, upload-time = "2021-06-07T09:01:07.073Z" } wheels = [ @@ -3273,8 +3588,8 @@ name = "pyobjc-framework-passkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e8/c8/200be798bb5569dad8b16a325f8b90c7656918af9394158d62afa86a3be9/pyobjc-framework-PassKit-7.3.tar.gz", hash = "sha256:10548941a9139bdd4469aeece4bb0aad7c5c28f57a19c54d7d78af6e779c5016", size = 30413, upload-time = "2021-06-07T09:01:09.222Z" } wheels = [ @@ -3287,8 +3602,8 @@ name = "pyobjc-framework-pencilkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/12/7d/1481d94fe38fbbdc1a605cd6fe330f5dd1a875898b7b6ba7ce35d6d653d7/pyobjc-framework-PencilKit-7.3.tar.gz", hash = "sha256:b2c12217c742e5acbffeb8d8b27f8a684ddfdbd0ade617db0865ae3c1955368a", size = 12241, upload-time = "2021-06-07T09:01:10.16Z" } wheels = [ @@ -3300,8 +3615,8 @@ name = "pyobjc-framework-photos" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/54/f0/eafd2cb1e659fb131913f8aecc60142e82ebd93c405af3d797700bfc0004/pyobjc-framework-Photos-7.3.tar.gz", hash = "sha256:cf96b97b94f3f3c922966fa7637436adcfb72c24acd3a21bda327fd151e8b4f1", size = 39205, upload-time = "2021-06-07T09:01:11.068Z" } wheels = [ @@ -3314,8 +3629,8 @@ name = "pyobjc-framework-photosui" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/68/0b/fe49a84e9c857a0d7922593d7662e89a07117a78ba8d5739c53e46ea7b64/pyobjc-framework-PhotosUI-7.3.tar.gz", hash = "sha256:34da58779d560949e9443ea79b26f36deb6e2a6ab17a8fc4f4d39d0190ba87a8", size = 24602, upload-time = "2021-06-07T09:01:12.042Z" } wheels = [ @@ -3328,8 +3643,8 @@ name = "pyobjc-framework-preferencepanes" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e0/f9/40669c2626c0bee4a71974a9e75794b7cedf8279a39691e7762a56910c47/pyobjc-framework-PreferencePanes-7.3.tar.gz", hash = "sha256:8aa2710d96d3d18f637ba53748225ed47ebc474fd0874cf8734c25d9c69f48f3", size = 23084, upload-time = "2021-06-07T09:01:13.107Z" } wheels = [ @@ -3341,8 +3656,8 @@ name = "pyobjc-framework-pushkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/14/769c4f2fcd1ab86b503b906d8d3ccece3cef097b7c5e746c9c2bafffa75c/pyobjc-framework-PushKit-7.3.tar.gz", hash = "sha256:063579734da899a19fd0b67f75085c2b4c2295793889594a66dcdb2a5bd8fd9a", size = 17888, upload-time = "2021-06-07T09:01:14.89Z" } wheels = [ @@ -3355,8 +3670,8 @@ name = "pyobjc-framework-quartz" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/92/77/d565a22274350f04bd9c5816d171c9e5cfd75e53b3f1dc52bb7171801ed3/pyobjc-framework-Quartz-7.3.tar.gz", hash = "sha256:98812844c34262def980bdf60923a875cd43428a8375b6fd53bd2cd800eccf0b", size = 3328902, upload-time = "2021-06-07T09:01:17.218Z" } @@ -3365,9 +3680,9 @@ name = "pyobjc-framework-quicklookthumbnailing" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/60/cf/9f93f1b50087265fd8ebd1c5dfe4b836f9f304297191a086c635855b1c72/pyobjc-framework-QuickLookThumbnailing-7.3.tar.gz", hash = "sha256:2308898f9c94370a99ab17fde0b713da0c9449ac22163cdb15e51a539834c3c7", size = 12872, upload-time = "2021-06-07T09:01:18.527Z" } wheels = [ @@ -3379,8 +3694,8 @@ name = "pyobjc-framework-replaykit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6f/a5/12456a24bb8a1c554717396a947a30962616b84063a2806d2fc6a20f7674/pyobjc-framework-ReplayKit-7.3.tar.gz", hash = "sha256:aec8f34fbbeb7aca9b4f1b285a4f2119035e4100249b8a64e84b144bb47a650d", size = 20947, upload-time = "2021-06-07T09:01:19.417Z" } wheels = [ @@ -3393,8 +3708,8 @@ name = "pyobjc-framework-safariservices" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/77/d3/556e9a19b25647fddcbd8477f60d80f1463fd5596455655aa1b10a992895/pyobjc-framework-SafariServices-7.3.tar.gz", hash = "sha256:fd3d6878f0fd80a03ff343f8379af8060e5f33058ce279047ecb6e12304216cb", size = 22668, upload-time = "2021-06-07T09:01:20.31Z" } wheels = [ @@ -3407,9 +3722,9 @@ name = "pyobjc-framework-scenekit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/eb/d6/c990f478b982a89566e76edadd4f5642458e06d978b0fdc8fdbae092d8f9/pyobjc-framework-SceneKit-7.3.tar.gz", hash = "sha256:4adc7e82784f5277f24305c08761936a329020f664fb7da4dc9b9b7a64990b1a", size = 109875, upload-time = "2021-06-07T09:01:21.258Z" } wheels = [ @@ -3422,8 +3737,8 @@ name = "pyobjc-framework-screensaver" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3d/03/5e12ac2f7330b9d5f3aae01438c20bf39bc4dbc00c1c930ea3f8cabab772/pyobjc-framework-ScreenSaver-7.3.tar.gz", hash = "sha256:b4d13cc2d54675893aed6d2fa60cf8d134fa821e9cce7b224756fa3e260a548f", size = 20982, upload-time = "2021-06-07T09:01:22.243Z" } wheels = [ @@ -3436,8 +3751,8 @@ name = "pyobjc-framework-screentime" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e2/db/f1432636c5ee85277ea84172a143d2fc7f489e9f7eae9abe82d9202e481c/pyobjc-framework-ScreenTime-7.3.tar.gz", hash = "sha256:96f25c23321f92eb4da9a75e10d778484e5a99e74e14971783354a5047f765ea", size = 10996, upload-time = "2021-06-07T09:01:23.154Z" } wheels = [ @@ -3449,8 +3764,8 @@ name = "pyobjc-framework-scriptingbridge" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5c/c2/4685abaaed429cd7c77af68dc2e43bccee07446c5ab4f92c8e9370b7872c/pyobjc-framework-ScriptingBridge-7.3.tar.gz", hash = "sha256:f09f4cad708d3c946bbcf7fdc5e623bbb512e4e0b085536fc22fe1131b517ca9", size = 19420, upload-time = "2021-06-07T09:01:24.435Z" } wheels = [ @@ -3463,8 +3778,8 @@ name = "pyobjc-framework-searchkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coreservices", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreservices", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/60/e8/139d829106918f376123b431d958d1b861bf71ec76297ff339d02f42b8f0/pyobjc-framework-SearchKit-7.3.tar.gz", hash = "sha256:80fc90c95cf14a0f4cc589764f329211e20e02f51840e880c802603c9dc41497", size = 29432, upload-time = "2021-06-07T09:01:25.376Z" } wheels = [ @@ -3476,8 +3791,8 @@ name = "pyobjc-framework-security" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b4/04/2ce0be4968fb0e6ad8bda15076e40cbce8c5b09628ef6a999eba041bc99b/pyobjc-framework-Security-7.3.tar.gz", hash = "sha256:4109ab15faf2dcf89646330a4f0a6584410d7134418fae0814858cab4ab76347", size = 113799, upload-time = "2021-06-07T09:01:26.787Z" } @@ -3486,9 +3801,9 @@ name = "pyobjc-framework-securityfoundation" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-security", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-security", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/36/7f/045a107fb75d0e4643d77733c443dca29b9810136f873f8db082896f9531/pyobjc-framework-SecurityFoundation-7.3.tar.gz", hash = "sha256:b37b2ebc737cf79dece2afadaeb1a93a2a1346280f38ffe4baa7681a9c3298ce", size = 10109, upload-time = "2021-06-07T09:01:27.893Z" } wheels = [ @@ -3500,9 +3815,9 @@ name = "pyobjc-framework-securityinterface" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-security", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-security", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a0/8f/dd369dac92478bdee5e3ae832df0ab6eca1bb254cd3eb07e7b9934a66672/pyobjc-framework-SecurityInterface-7.3.tar.gz", hash = "sha256:e240be5bd5de8783bd98a36018a51a104a267459ce527af8b28b22f66ee299ce", size = 23961, upload-time = "2021-06-07T09:01:29.122Z" } wheels = [ @@ -3515,8 +3830,8 @@ name = "pyobjc-framework-servernotification" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e3/92/e64fcdde350d2830a8e332beaa8e0d8a7e05c38ff0c09f91a51d59a05a39/pyobjc-framework-ServerNotification-7.3.tar.gz", hash = "sha256:aa8ba576a020a567016d36c6ce5fd9f6f8bd0f93c2bfb2b07420eb54ba514cd8", size = 10760, upload-time = "2021-06-07T09:01:30.133Z" } wheels = [ @@ -3528,8 +3843,8 @@ name = "pyobjc-framework-servicemanagement" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/df/67/d43dedbb4cf04dd98a4b7fd9d77dbdcd6ec945190f637744349dce0d6b84/pyobjc-framework-ServiceManagement-7.3.tar.gz", hash = "sha256:f3106b96347c7bf60045ffaee917235442cd1d9254a03e10f9bc648ccbbc3b55", size = 12178, upload-time = "2021-06-07T09:01:31.11Z" } wheels = [ @@ -3541,8 +3856,8 @@ name = "pyobjc-framework-social" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/93/bb/e9100c96ada01df58dc65c1c6ae204701c44cecb6df2d006f78cee34a86b/pyobjc-framework-Social-7.3.tar.gz", hash = "sha256:bc6f5e1566ae47d2083d9dc9d0903210b934e5abdc81a211f10ff0fa05df1e0d", size = 11665, upload-time = "2021-06-07T09:01:31.946Z" } wheels = [ @@ -3554,8 +3869,8 @@ name = "pyobjc-framework-soundanalysis" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/90/18/b6ccec63a607b7f8723d9cc2c588c81df153e4cfbe42b13f0db8e9e1c649/pyobjc-framework-SoundAnalysis-7.3.tar.gz", hash = "sha256:702cd6a3ff022370421182244161310551fe4927aea20b89f66615c7abc859eb", size = 11929, upload-time = "2021-06-07T09:01:32.784Z" } wheels = [ @@ -3567,8 +3882,8 @@ name = "pyobjc-framework-speech" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ad/51/4fae0ec3f9259e6878bc141aae681eb2f27b396cad8c57e4f2e0ff7a7abd/pyobjc-framework-Speech-7.3.tar.gz", hash = "sha256:9c6ef27d8381a065e43c23101c24d23d4f2a3d1ae62ee8afd5d36de1781f3e64", size = 20185, upload-time = "2021-06-07T09:01:34.053Z" } wheels = [ @@ -3581,9 +3896,9 @@ name = "pyobjc-framework-spritekit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/14/69/ff499dda40241cb089687d7dbdeabd16b8ff7fcbb177d088cfb4ef95ecdc/pyobjc-framework-SpriteKit-7.3.tar.gz", hash = "sha256:0a6a6a0821e8eacf56f847a1b68c62db6484b37588a84677aca44e2a41c39c67", size = 53683, upload-time = "2021-06-07T09:01:34.986Z" } wheels = [ @@ -3596,8 +3911,8 @@ name = "pyobjc-framework-storekit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/76/b7/75c4a2279ec8d6f79920ac87287dd97e29183e5170c5904fc201e8826f1c/pyobjc-framework-StoreKit-7.3.tar.gz", hash = "sha256:b9542b8a2a3ef7feb27ef6de7819b0657ec51db78235a5004f7d1444c0f19f56", size = 31725, upload-time = "2021-06-07T09:01:36.27Z" } wheels = [ @@ -3610,9 +3925,9 @@ name = "pyobjc-framework-syncservices" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coredata", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coredata", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/18/ed/f23e0312c1af8aa71aa68bd90a78866d26ca4e9fc8723d927a292d01a63d/pyobjc-framework-SyncServices-7.3.tar.gz", hash = "sha256:e63bba4e855d1683d249017fbbbb09a8699f9258f3214014aa3ba4341506e165", size = 35906, upload-time = "2021-06-07T09:01:37.808Z" } wheels = [ @@ -3625,8 +3940,8 @@ name = "pyobjc-framework-systemconfiguration" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/03/6d/1031ccab0a255a0c795de397889ad5400661e26a230e23903a529fd0018f/pyobjc-framework-SystemConfiguration-7.3.tar.gz", hash = "sha256:92cbe14d9efcf1c52328ab1ba4cc359879c22e2f390179ec4713af176bc19dc6", size = 73379, upload-time = "2021-06-07T09:01:38.85Z" } wheels = [ @@ -3639,8 +3954,8 @@ name = "pyobjc-framework-systemextensions" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/85/8b/b366da23789d06f591b1a62e40916539fe4dd7160fd40b993fe0f80a77bf/pyobjc-framework-SystemExtensions-7.3.tar.gz", hash = "sha256:d175f0fba9a571af78c333285f5b1cd310e83453dc018ae5663adcd53aef4d0d", size = 18317, upload-time = "2021-06-07T09:01:39.846Z" } wheels = [ @@ -3653,8 +3968,8 @@ name = "pyobjc-framework-uniformtypeidentifiers" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/18/7b/779841230336bcde414b1c0e7cea5c6b007920675cbddf10f54c5817978b/pyobjc-framework-UniformTypeIdentifiers-7.3.tar.gz", hash = "sha256:f827ca61d5dcd82343178d1d6a6a5e9be8f721f51a4feba4c3a3a39afaa674d5", size = 13577, upload-time = "2021-06-07T09:01:40.799Z" } wheels = [ @@ -3666,8 +3981,8 @@ name = "pyobjc-framework-usernotifications" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/20/da/aa2a21b33b2e2f4871fdf2023c6f925a9ec703224feaba409dc2ecc7386c/pyobjc-framework-UserNotifications-7.3.tar.gz", hash = "sha256:40f60d4d0eb575e5d23d3d0bb5fcbdf444cf80ce91f5235c634e336416f91934", size = 22961, upload-time = "2021-06-07T09:01:41.686Z" } wheels = [ @@ -3680,9 +3995,9 @@ name = "pyobjc-framework-usernotificationsui" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-usernotifications", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-usernotifications", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0b/25/71fd6d7ce214ac47e3ca6b718b9e622b3497801fd8321a233faa295435ec/pyobjc-framework-UserNotificationsUI-7.3.tar.gz", hash = "sha256:02b639f06d0a394b4fd45068c6b74250f1033049d74f1a2b2533822aa114605b", size = 11004, upload-time = "2021-06-07T09:01:42.596Z" } wheels = [ @@ -3694,8 +4009,8 @@ name = "pyobjc-framework-videosubscriberaccount" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a7/1f/33e729d6762a24e0c1b2d292979d6ec3c2da32d0253575201fa6d5c1cea9/pyobjc-framework-VideoSubscriberAccount-7.3.tar.gz", hash = "sha256:0dddf8bbfe70e1fd1e5ef4d29fff097c00f33357807a958676d3b52944eaebfa", size = 12789, upload-time = "2021-06-07T09:01:43.427Z" } wheels = [ @@ -3707,10 +4022,10 @@ name = "pyobjc-framework-videotoolbox" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coremedia", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e5/f6/0b99d715c998ab3369be9d2277fd528398e70d3c6b15f2920e0eabf5437e/pyobjc-framework-VideoToolbox-7.3.tar.gz", hash = "sha256:e32eb1374dd42f4dc8d8bddb7f7f48dde0d7e1fde7181effdf15df8144b85c8e", size = 37110, upload-time = "2021-06-07T09:01:44.421Z" } wheels = [ @@ -3723,8 +4038,8 @@ name = "pyobjc-framework-virtualization" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/09/cf/2a0e79b59bc30e964be73452dddf25c52ad337b291bb13266e6b1bafa690/pyobjc-framework-Virtualization-7.3.tar.gz", hash = "sha256:57f8ec5386f063d281a2c235cf1f1ef5181f2376cd53bd484018e50b4dcf2eb8", size = 21250, upload-time = "2021-06-07T09:01:45.378Z" } wheels = [ @@ -3737,10 +4052,10 @@ name = "pyobjc-framework-vision" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-coreml", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-quartz", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreml", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a6/ec/fd5e60f7cc0b44474e3ad71a3cebfed3acf862df76e19b1f0ab3d72697c3/pyobjc-framework-Vision-7.3.tar.gz", hash = "sha256:cab1fdf6b02a1767646cf6353a118c0fa5d420fca4ab3904ce5054332f59f424", size = 41848, upload-time = "2021-06-07T09:01:46.364Z" } wheels = [ @@ -3753,8 +4068,8 @@ name = "pyobjc-framework-webkit" version = "7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, - { name = "pyobjc-framework-cocoa", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5a/96/3a71145beb8563d47848fb5c10906654406bba7e49120d30416356b8cc16/pyobjc-framework-WebKit-7.3.tar.gz", hash = "sha256:bec3a985c0f5e4263d6e28e2c551c1b5ec7b63950e0e3cb5409abdbf61f11f01", size = 385737, upload-time = "2021-06-07T09:01:47.575Z" } wheels = [ @@ -3793,56 +4108,18 @@ wheels = [ ] [[package]] -name = "pyqt6" -version = "6.10.2" +name = "pyqmix" +version = "2021.1.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyqt6-qt6" }, - { name = "pyqt6-sip" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/96/03/e756f52e8b0d7bb5527baf8c46d59af0746391943bdb8655acba22ee4168/pyqt6-6.10.2.tar.gz", hash = "sha256:6c0db5d8cbb9a3e7e2b5b51d0ff3f283121fa27b864db6d2f35b663c9be5cc83", size = 1085573, upload-time = "2026-01-08T16:40:00.244Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/3f/f073a980969aa485ef288eb2e3b94c223ba9c7ac9941543f19b51659b98d/pyqt6-6.10.2-cp39-abi3-macosx_10_14_universal2.whl", hash = "sha256:37ae7c1183fe4dd0c6aefd2006a35731245de1cb6f817bb9e414a3e4848dfd6d", size = 60244482, upload-time = "2026-01-08T16:38:50.837Z" }, - { url = "https://files.pythonhosted.org/packages/ec/3e/9a015651ec71cea2e2f960c37edeb21623ba96a74956c0827def837f7c6b/pyqt6-6.10.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:78e1b3d5763e4cbc84485aef600e0aba5e1932fd263b716f92cd1a40dfa5e924", size = 37899440, upload-time = "2026-01-08T16:39:09.027Z" }, - { url = "https://files.pythonhosted.org/packages/51/74/a88fec2b99700270ca5d7dc7d650236a4990ed6fc88e055ca0fc8a339ee3/pyqt6-6.10.2-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:bbc3af541bbecd27301bfe69fe445aa1611a9b490bd3de77306b12df632f7ec6", size = 40748467, upload-time = "2026-01-08T16:39:29.551Z" }, - { url = "https://files.pythonhosted.org/packages/75/34/be7a55529607b21db00a49ca53cb07c3092d2a5a95ea19bb95cfa0346904/pyqt6-6.10.2-cp39-abi3-win_amd64.whl", hash = "sha256:bd328cb70bc382c48861cd5f0a11b2b8ae6f5692d5a2d6679ba52785dced327b", size = 26015391, upload-time = "2026-01-08T16:39:42.946Z" }, - { url = "https://files.pythonhosted.org/packages/af/de/d9c88f976602b7884fec4ad54a4575d48e23e4f390e5357ea83917358846/pyqt6-6.10.2-cp39-abi3-win_arm64.whl", hash = "sha256:7901ba1df024b7ee9fdacfb2b7661aeb3749ae8b0bef65428077de3e0450eabb", size = 26208415, upload-time = "2026-01-08T16:39:57.751Z" }, -] - -[[package]] -name = "pyqt6-qt6" -version = "6.10.2" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/eb/f04d547d8ed9f20c7b246db4ef5d93b49cab4692009a10652ed0a8b9d2aa/pyqt6_qt6-6.10.2-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:5761cfccc721da2311c3f1213577f0ff1df07bbbbe3fa3a209a256b82cf057e3", size = 68688870, upload-time = "2026-01-29T12:26:48.619Z" }, - { url = "https://files.pythonhosted.org/packages/ce/c8/d99e65ab01c2402fb6bc4f77abef7244f7d5fb2f2e6d5b0abdf71bb2e4fc/pyqt6_qt6-6.10.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:6dda853a8db1b8d1a2ddbbe76cc6c3aa86614cad14056bd3c0435d8feea73b2d", size = 62512013, upload-time = "2026-01-29T12:27:24.642Z" }, - { url = "https://files.pythonhosted.org/packages/d5/fe/01fd9b9d2ca139ef61582f2e2da249fa169229144294c1bb27db59ad8420/pyqt6_qt6-6.10.2-py3-none-manylinux_2_34_x86_64.whl", hash = "sha256:19c10b5f0806e9f9bac2c9759bd5d7d19a78967f330fd60a2db409177fa76e49", size = 84028760, upload-time = "2026-01-29T12:28:03.267Z" }, - { url = "https://files.pythonhosted.org/packages/f4/20/a0d027ebb267d3afaf319d94efe1ff4d667004ee83b96701329a4d11fb95/pyqt6_qt6-6.10.2-py3-none-manylinux_2_39_aarch64.whl", hash = "sha256:2e60d616861ca4565cd295418d605975aa2dc407ba4b94c1586a70c92e9cb052", size = 83063975, upload-time = "2026-01-29T12:28:48.928Z" }, - { url = "https://files.pythonhosted.org/packages/06/8e/595f215876d507417cc8565e05519916d3b0b76baedea6a1e4e5105633fc/pyqt6_qt6-6.10.2-py3-none-win_amd64.whl", hash = "sha256:c4b7f7d66cc58bddf1bc1ca28dfcf7a45f58cfcb11d81d13a0510409dd4957ac", size = 78433821, upload-time = "2026-01-29T12:29:35.493Z" }, - { url = "https://files.pythonhosted.org/packages/50/5f/2196e2b536217b87cb3d2ce13ef8f7607d08b02f1990a4bd84a88d293a3c/pyqt6_qt6-6.10.2-py3-none-win_arm64.whl", hash = "sha256:7164a6f0c1335358a3026df9865c8f75395b01f60f0dcd2f66c029ec16fc83d2", size = 58354426, upload-time = "2026-01-29T12:30:02.95Z" }, + { name = "appdirs", marker = "sys_platform == 'win32'" }, + { name = "cffi", marker = "sys_platform == 'win32'" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "ruamel-yaml", marker = "sys_platform == 'win32'" }, ] - -[[package]] -name = "pyqt6-sip" -version = "13.11.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/24/a753e1af94b9ae5b2da63d4598457308da3cdbf0838c959381db086ccc86/pyqt6_sip-13.11.1.tar.gz", hash = "sha256:869c5b48afe38e55b1ee0dd72182b0886e968cc509b98023ff50010b013ce1be", size = 92574, upload-time = "2026-03-09T13:01:35.418Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/0c/9b2bcdc447a8cffe4783e37deb938f259368404d68393f97dc8e7d20f70d/pyqmix-2021.1.2.tar.gz", hash = "sha256:02d22b0b39afb0e2af4323a10906ae98648531d6c1db2b187549503fee17d592", size = 58376, upload-time = "2021-05-14T06:25:31.918Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/27/47598e701d284497216bf97bf8b6a69f5e61412e716c232ff2b7e6cb2100/pyqt6_sip-13.11.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ba9d362dd1e54b43bc2594f8841e1e39d24789716d28f08e5c9282af9fca342c", size = 112564, upload-time = "2026-03-09T13:01:14.628Z" }, - { url = "https://files.pythonhosted.org/packages/95/cb/116f9b328636765f3bce97d9e10ec041c54bbe92beb0617edb86c2b615c1/pyqt6_sip-13.11.1-cp312-cp312-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0df15849946cea969d3ff2b24b76149262b6044aea2c5403e4f70c24c973a4c8", size = 299564, upload-time = "2026-03-09T13:01:17.292Z" }, - { url = "https://files.pythonhosted.org/packages/1b/be/fe2321285e8f683e705d199dbb458131f1850dc5966155a19c40100c85bb/pyqt6_sip-13.11.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c52b2b27fc77d9447a8dc1c6de1aaccc22d41e48697aafb2f2f20b8984bb02a5", size = 321210, upload-time = "2026-03-09T13:01:15.904Z" }, - { url = "https://files.pythonhosted.org/packages/ec/9b/7d4b10f9cba1b6f581dfb4860b9d11898da55a5ed3b8a6e7a1bf9f7084d0/pyqt6_sip-13.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:1d1c67179c1924b28e3d7f04585639e7a7c0946f62390efc6ccf2a6206e595d3", size = 53351, upload-time = "2026-03-09T13:01:19.327Z" }, - { url = "https://files.pythonhosted.org/packages/06/72/6c4e6f21cafa4bed40d2b0c1563525b0d8bfcb5734493696f4cfd043b45f/pyqt6_sip-13.11.1-cp312-cp312-win_arm64.whl", hash = "sha256:d83543125fe9fdb153e7e446c3b4d056d80ab5953644660633ab3f80e7784194", size = 48746, upload-time = "2026-03-09T13:01:20.248Z" }, - { url = "https://files.pythonhosted.org/packages/ee/0b/dc76c463c203e630b2c6417d4d5e337e919a265ac1c10127ef413551f5de/pyqt6_sip-13.11.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0c6d097aae7df312519e2b36e001bd796f6a2ce060ab8b9ed793daa8f407fe2e", size = 112552, upload-time = "2026-03-09T13:01:21.493Z" }, - { url = "https://files.pythonhosted.org/packages/d4/e3/65b605759859d38231ce7544065d4c61f891eb7766c351318e2a0b08a473/pyqt6_sip-13.11.1-cp313-cp313-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a72f4ebdab16a8a484019ff593de90d8013d3286b678c6ba1c0bdb117f4fcb13", size = 299932, upload-time = "2026-03-09T13:01:24.912Z" }, - { url = "https://files.pythonhosted.org/packages/60/f7/c10d2dd5bf503a1de83bd163467bd323f12af016866c2814743b5b1efe1c/pyqt6_sip-13.11.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b68e442efc4275651bf63f2c43713e242924fd948909e31cf8f20d783ca505e9", size = 321497, upload-time = "2026-03-09T13:01:22.724Z" }, - { url = "https://files.pythonhosted.org/packages/e1/1f/e7e5ad77a76c00db5c8c1b9960f2b0672ec1978b971bb3509858cd7a9458/pyqt6_sip-13.11.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca24bfd4d5d8274e338433df9ac41930650088c00018d3313c6bd8de21772a02", size = 53371, upload-time = "2026-03-09T13:01:26.286Z" }, - { url = "https://files.pythonhosted.org/packages/36/ef/a7acaf44980aed6fe26f1320e265db528fecb6a47ac67829c7cd011e9821/pyqt6_sip-13.11.1-cp313-cp313-win_arm64.whl", hash = "sha256:f532144c43f2fddcccf2e25df50cdb4a744edb4ce4ba5ed2d0f2cef825197f2f", size = 48745, upload-time = "2026-03-09T13:01:27.212Z" }, - { url = "https://files.pythonhosted.org/packages/20/1d/62c633faedef5bb3b8c7486a72e8a6466adaa2a14efcfccf85bb23426748/pyqt6_sip-13.11.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:cb931c1af45294bbe8039c5cfda184e3023f5dc766fc884964010eedd8fd85db", size = 112678, upload-time = "2026-03-09T13:01:28.15Z" }, - { url = "https://files.pythonhosted.org/packages/03/72/5a3d9ffef0caa7e1bc7a35d6300f6099bfccd1d8a485b4320ba20013a2d9/pyqt6_sip-13.11.1-cp314-cp314-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:353d613129316e9f7eda6bbe821deb7b7ffa14483499189171fd8a246873f9ac", size = 299560, upload-time = "2026-03-09T13:01:32.134Z" }, - { url = "https://files.pythonhosted.org/packages/98/f4/886f901f1e04da717a11e180ba19a9c7fc62da170966d57206006f173bda/pyqt6_sip-13.11.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fcadd68e09ee24cdda8f8bfcba52e59c9b297055d2c450f0eb89afa61a8dc31a", size = 321846, upload-time = "2026-03-09T13:01:29.817Z" }, - { url = "https://files.pythonhosted.org/packages/96/f2/b68fd566f7f86dbb53d933489e70487cabaea0e0161690e4899653bbc7fb/pyqt6_sip-13.11.1-cp314-cp314-win_amd64.whl", hash = "sha256:581e287bf42587593b88b30d9db06ed0fccbf40f345a5bd3ec3f00a5692e2430", size = 55055, upload-time = "2026-03-09T13:01:33.467Z" }, - { url = "https://files.pythonhosted.org/packages/8d/42/efb7ced69f7d1d31eb8f19b2d778aeb182be7e070569d02b9057ac478e3e/pyqt6_sip-13.11.1-cp314-cp314-win_arm64.whl", hash = "sha256:42b62530a9b6a9c6e29c2941b8ab78258652da0aeae4eb1fc9a0631d19a7a7b2", size = 49597, upload-time = "2026-03-09T13:01:34.49Z" }, + { url = "https://files.pythonhosted.org/packages/7a/c2/e0db33f532cf5ec6b2fbbfaf8408882752f86831ca3904a16a543502ddcf/pyqmix-2021.1.2-py2.py3-none-any.whl", hash = "sha256:4de542a216df9597cadeb02b53feb809f7a80e7b12de4c2d7d0aec058a68c102", size = 39987, upload-time = "2021-05-14T06:25:30.43Z" }, ] [[package]] @@ -3910,17 +4187,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] +[[package]] +name = "python-dotenv" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, +] + [[package]] name = "python-gitlab" -version = "8.1.0" +version = "8.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, { name = "requests-toolbelt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/20/1d/a62fea1f3312fd9e58af41466ae072796a09684dd0cd825cc042ba39488c/python_gitlab-8.1.0.tar.gz", hash = "sha256:660f15e3f889ec430797d260322bc61d90f8d90accfc10ba37593b11aed371bd", size = 401576, upload-time = "2026-02-28T01:26:32.757Z" } +sdist = { url = "https://files.pythonhosted.org/packages/77/9c/ec0073c260812bca170418e8e259a2ed0728200af4b3f7120badf2e6f05a/python_gitlab-8.2.0.tar.gz", hash = "sha256:de874dc538db6dceb48929f4c8fb55d6064dd19cb3ffdad1100190f835c5b674", size = 407110, upload-time = "2026-03-28T01:50:07.66Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/79/d4/9848be62ef23fcac203f4386faf43a2cc13a4888447b3f5fbf7346f31374/python_gitlab-8.1.0-py3-none-any.whl", hash = "sha256:b1a59e81e5e0363185b446a707dc92c27ee8bf1fc14ce75ed8eafa58cbdce63a", size = 144498, upload-time = "2026-02-28T01:26:31.14Z" }, + { url = "https://files.pythonhosted.org/packages/38/ee/a61bb562bdf6f0bc6c51cdcf80ab5503cbb4b2f5053fa4b054cc0a56e48a/python_gitlab-8.2.0-py3-none-any.whl", hash = "sha256:884618d4d60beadb21bb0c5f0cca46e70c6e501784f136bf0b6f85f5bc15ce62", size = 147477, upload-time = "2026-03-28T01:50:06.237Z" }, ] [[package]] @@ -3929,7 +4215,8 @@ version = "3.0.11115" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", - "python_full_version < '3.14' and sys_platform == 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'win32'", + "python_full_version < '3.13' and sys_platform == 'win32'", ] sdist = { url = "https://files.pythonhosted.org/packages/fd/2d/f5ab9a8fb34db780364b980bfac6dd2fa750ecd7c9c299a8b728f924262c/python-vlc-3.0.11115.tar.gz", hash = "sha256:a4d3bdddfce84a8fb1b2d5447193a0239c55c16ca246e5194d48efd59c4e236b", size = 148303, upload-time = "2020-07-25T13:12:38.312Z" } wheels = [ @@ -3942,9 +4229,14 @@ version = "3.0.21203" source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.14' and sys_platform == 'emscripten'", - "python_full_version < '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version >= '3.14' and sys_platform == 'darwin'", + "python_full_version >= '3.14' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'emscripten'", + "python_full_version < '3.13' and sys_platform == 'emscripten'", + "python_full_version == '3.13.*' and sys_platform == 'darwin'", + "python_full_version < '3.13' and sys_platform == 'darwin'", + "python_full_version == '3.13.*' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version < '3.13' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] sdist = { url = "https://files.pythonhosted.org/packages/4b/5b/f9ce6f0c9877b6fe5eafbade55e0dcb6b2b30f1c2c95837aef40e390d63b/python_vlc-3.0.21203.tar.gz", hash = "sha256:52d0544b276b11e58b6c0b748c3e0518f94f74b1b4cd328c83a59eacabead1ec", size = 162211, upload-time = "2024-10-07T14:39:54.755Z" } wheels = [ @@ -3956,7 +4248,7 @@ name = "python-xlib" version = "0.33" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "six", marker = "sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/86/f5/8c0653e5bb54e0cbdfe27bf32d41f27bc4e12faa8742778c17f2a71be2c0/python-xlib-0.33.tar.gz", hash = "sha256:55af7906a2c75ce6cb280a584776080602444f75815a7aff4d287bb2d7018b32", size = 269068, upload-time = "2022-12-25T18:53:00.824Z" } wheels = [ @@ -4094,7 +4386,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.5" +version = "2.33.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -4102,9 +4394,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -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" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, + { url = "https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a", size = 64947, upload-time = "2026-03-30T16:09:13.83Z" }, ] [[package]] @@ -4128,6 +4420,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/54/6f679c435d28e0a568d8e8a7c0a93a09010818634c3c3907fc98d8983770/roman_numerals-4.1.0-py3-none-any.whl", hash = "sha256:647ba99caddc2cc1e55a51e4360689115551bf4476d90e8162cf8c345fe233c7", size = 7676, upload-time = "2025-12-17T18:25:33.098Z" }, ] +[[package]] +name = "ruamel-yaml" +version = "0.16.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/29/1802b876055ca17f8cdcdb855c0806e85c3cfdae68421d722991fa728dd9/ruamel.yaml-0.16.3.tar.gz", hash = "sha256:7c58dd06488cdb0bf95cc089aac84318a11f170272581351dda93f2a507c7419", size = 145579, upload-time = "2019-08-15T20:38:33.191Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/6b/4efd4343dd65b1196384afc0a859495b3c274b46bc4ce0ec3b9df29a804e/ruamel.yaml-0.16.3-py2.py3-none-any.whl", hash = "sha256:f43388cfbfe650035204a831f57ff0acacf61bbe10406971d21d7d0ee0faa56b", size = 123089, upload-time = "2019-08-15T20:38:37.138Z" }, +] + [[package]] name = "scipy" version = "1.17.1" @@ -4191,23 +4492,23 @@ wheels = [ [[package]] name = "scipy-stubs" -version = "1.17.1.1" +version = "1.17.1.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "optype", extra = ["numpy"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ec/c1/bf50e1cbf4015d4077835ffebea9a45dba7f5bf1cd781e931baff358cb20/scipy_stubs-1.17.1.1.tar.gz", hash = "sha256:e8f812a6eb298cfa3dd6b79a4af2b00fb4045f2ee28eadcc0eee8882208b5f1a", size = 383682, upload-time = "2026-03-08T21:49:40.976Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d1/75/d944a11fca64aa84fbb4bfcf613b758319c6103cb30a304a0e9727009d62/scipy_stubs-1.17.1.4.tar.gz", hash = "sha256:cae00c5207aa62ceb4bcadea202d9fbbf002e958f9e4de981720436b8d5c1802", size = 396980, upload-time = "2026-04-13T11:46:54.528Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/23/15d568084d57cc99ba9f662f06c0fa647348b809df28bef1907aa8149eec/scipy_stubs-1.17.1.1-py3-none-any.whl", hash = "sha256:26576c5ed0f9007a07f4f4582f984c9bfac00ac93c268c6e558ad5ead0312b43", size = 589301, upload-time = "2026-03-08T21:49:38.794Z" }, + { url = "https://files.pythonhosted.org/packages/92/f8/334aa5a7a482ea89cb14d92f6a4d9ffa1e193e733144d4d14c7ffcb33583/scipy_stubs-1.17.1.4-py3-none-any.whl", hash = "sha256:e6e5c390fb864745bc3d5f591de81f5cb4f84403857d4f660acb5b6339956f5b", size = 604752, upload-time = "2026-04-13T11:46:53.135Z" }, ] [[package]] name = "setuptools" -version = "70.3.0" +version = "82.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/d8/10a70e86f6c28ae59f101a9de6d77bf70f147180fbf40c3af0f64080adc3/setuptools-70.3.0.tar.gz", hash = "sha256:f171bab1dfbc86b132997f26a119f6056a57950d058587841a0082e8830f9dc5", size = 2333112, upload-time = "2024-07-09T16:08:06.251Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/15/88e46eb9387e905704b69849618e699dc2f54407d8953cc4ec4b8b46528d/setuptools-70.3.0-py3-none-any.whl", hash = "sha256:fe384da74336c398e0d956d1cae0669bc02eed936cdb1d49b57de1990dc11ffc", size = 931070, upload-time = "2024-07-09T16:07:58.829Z" }, + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, ] [[package]] @@ -4249,6 +4550,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, ] +[[package]] +name = "sounddevice" +version = "0.5.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2a/f9/2592608737553638fca98e21e54bfec40bf577bb98a61b2770c912aab25e/sounddevice-0.5.5.tar.gz", hash = "sha256:22487b65198cb5bf2208755105b524f78ad173e5ab6b445bdab1c989f6698df3", size = 143191, upload-time = "2026-01-23T18:36:43.529Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/0a/478e441fd049002cf308520c0d62dd8333e7c6cc8d997f0dda07b9fbcc46/sounddevice-0.5.5-py3-none-any.whl", hash = "sha256:30ff99f6c107f49d25ad16a45cacd8d91c25a1bcdd3e81a206b921a3a6405b1f", size = 32807, upload-time = "2026-01-23T18:36:35.649Z" }, + { url = "https://files.pythonhosted.org/packages/56/f9/c037c35f6d0b6bc3bc7bfb314f1d6f1f9a341328ef47cd63fc4f850a7b27/sounddevice-0.5.5-py3-none-macosx_10_6_x86_64.macosx_10_6_universal2.whl", hash = "sha256:05eb9fd6c54c38d67741441c19164c0dae8ce80453af2d8c4ad2e7823d15b722", size = 108557, upload-time = "2026-01-23T18:36:37.41Z" }, + { url = "https://files.pythonhosted.org/packages/88/a1/d19dd9889cd4bce2e233c4fac007cd8daaf5b9fe6e6a5d432cf17be0b807/sounddevice-0.5.5-py3-none-win32.whl", hash = "sha256:1234cc9b4c9df97b6cbe748146ae0ec64dd7d6e44739e8e42eaa5b595313a103", size = 317765, upload-time = "2026-01-23T18:36:39.047Z" }, + { url = "https://files.pythonhosted.org/packages/c3/0e/002ed7c4c1c2ab69031f78989d3b789fee3a7fba9e586eb2b81688bf4961/sounddevice-0.5.5-py3-none-win_amd64.whl", hash = "sha256:cfc6b2c49fb7f555591c78cb8ecf48d6a637fd5b6e1db5fec6ed9365d64b3519", size = 365324, upload-time = "2026-01-23T18:36:40.496Z" }, + { url = "https://files.pythonhosted.org/packages/4e/39/a61d4b83a7746b70d23d9173be688c0c6bfc7173772344b7442c2c155497/sounddevice-0.5.5-py3-none-win_arm64.whl", hash = "sha256:3861901ddd8230d2e0e8ae62ac320cdd4c688d81df89da036dcb812f757bb3e6", size = 317115, upload-time = "2026-01-23T18:36:42.235Z" }, +] + [[package]] name = "soundfile" version = "0.13.1" @@ -4277,6 +4594,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016, upload-time = "2026-01-20T04:27:01.012Z" }, ] +[[package]] +name = "speechrecognition" +version = "3.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "audioop-lts", marker = "python_full_version >= '3.13'" }, + { name = "standard-aifc", marker = "python_full_version >= '3.13'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/68/903023341b71dcb0fb2f58984bbd4d0483ed0205f6e3e638aa0cb0442c63/speechrecognition-3.16.0.tar.gz", hash = "sha256:32100621e13ffa58df3c962f7c9e0f1f092be7be305fa5bd9579581d17b78191", size = 32855936, upload-time = "2026-04-05T14:54:40.29Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/6f/a795d6d9c95e14404e381708fb96dbdfc6156ddf20484633a9800847c19c/speechrecognition-3.16.0-py3-none-any.whl", hash = "sha256:045ad40fe255544aea7b1b6182f2b7ba4aa637286f5a1ddb04a75cc808df9718", size = 32853265, upload-time = "2026-04-05T14:54:34.967Z" }, +] + [[package]] name = "sphinx" version = "9.1.0" @@ -4320,16 +4651,16 @@ wheels = [ [[package]] name = "sphinx-markdown-builder" -version = "0.6.9" +version = "0.6.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docutils" }, { name = "sphinx" }, { name = "tabulate" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d2/f6/7566ba54c8b9744192bdf19ba01e62e1bb6cb1e8526447cdb29feb7cac7c/sphinx_markdown_builder-0.6.9.tar.gz", hash = "sha256:e89dc1b9eb837da430c2c230011fad95a3dfab0345ad503a32e35a31d284a722", size = 22707, upload-time = "2025-12-07T14:36:14.088Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/58/0b7b9a7d071140b3705885d51932e8b62f520388c2772e4952189971727b/sphinx_markdown_builder-0.6.10.tar.gz", hash = "sha256:cd5acf88d52ea0146a712fd557404f10326dff3428a78ba928e59b1727fd4a86", size = 22688, upload-time = "2026-03-11T10:56:57.639Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/ee/02f9986d7818be2ccc5bce76d388e73f5a163f604f682d1ad69e6bc0df7c/sphinx_markdown_builder-0.6.9-py3-none-any.whl", hash = "sha256:35b555760c48d4a38fe4b27813cb5ca636bbd22d8ef0742ac6959043f8000840", size = 16717, upload-time = "2025-12-07T14:36:12.646Z" }, + { url = "https://files.pythonhosted.org/packages/c2/8f/9fecf3d081d5cd49eff83a17b9fef50ed741e6223ab3bb906de4ab0068f9/sphinx_markdown_builder-0.6.10-py3-none-any.whl", hash = "sha256:16d86738b9ac69fcbc86e373c31c6402c30af1fa8d98d0f62cc5f38bfe5fc26e", size = 16700, upload-time = "2026-03-11T10:56:56.135Z" }, ] [[package]] @@ -4386,6 +4717,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, ] +[[package]] +name = "standard-aifc" +version = "3.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "audioop-lts", marker = "python_full_version >= '3.13'" }, + { name = "standard-chunk", marker = "python_full_version >= '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/53/6050dc3dde1671eb3db592c13b55a8005e5040131f7509cef0215212cb84/standard_aifc-3.13.0.tar.gz", hash = "sha256:64e249c7cb4b3daf2fdba4e95721f811bde8bdfc43ad9f936589b7bb2fae2e43", size = 15240, upload-time = "2024-10-30T16:01:31.772Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/52/5fbb203394cc852334d1575cc020f6bcec768d2265355984dfd361968f36/standard_aifc-3.13.0-py3-none-any.whl", hash = "sha256:f7ae09cc57de1224a0dd8e3eb8f73830be7c3d0bc485de4c1f82b4a7f645ac66", size = 10492, upload-time = "2024-10-30T16:01:07.071Z" }, +] + +[[package]] +name = "standard-chunk" +version = "3.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/06/ce1bb165c1f111c7d23a1ad17204d67224baa69725bb6857a264db61beaf/standard_chunk-3.13.0.tar.gz", hash = "sha256:4ac345d37d7e686d2755e01836b8d98eda0d1a3ee90375e597ae43aaf064d654", size = 4672, upload-time = "2024-10-30T16:18:28.326Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/90/a5c1084d87767d787a6caba615aa50dc587229646308d9420c960cb5e4c0/standard_chunk-3.13.0-py3-none-any.whl", hash = "sha256:17880a26c285189c644bd5bd8f8ed2bdb795d216e3293e6dbe55bbd848e2982c", size = 4944, upload-time = "2024-10-30T16:18:26.694Z" }, +] + [[package]] name = "tables" version = "3.11.1" @@ -4451,26 +4804,26 @@ wheels = [ [[package]] name = "types-requests" -version = "2.32.4.20260107" +version = "2.33.0.20260408" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0f/f3/a0663907082280664d745929205a89d41dffb29e89a50f753af7d57d0a96/types_requests-2.32.4.20260107.tar.gz", hash = "sha256:018a11ac158f801bfa84857ddec1650750e393df8a004a8a9ae2a9bec6fcb24f", size = 23165, upload-time = "2026-01-07T03:20:54.091Z" } +sdist = { url = "https://files.pythonhosted.org/packages/69/6a/749dc53a54a3f35842c1f8197b3ca6b54af6d7458a1bfc75f6629b6da666/types_requests-2.33.0.20260408.tar.gz", hash = "sha256:95b9a86376807a216b2fb412b47617b202091c3ea7c078f47cc358d5528ccb7b", size = 23882, upload-time = "2026-04-08T04:34:49.33Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1c/12/709ea261f2bf91ef0a26a9eed20f2623227a8ed85610c1e54c5805692ecb/types_requests-2.32.4.20260107-py3-none-any.whl", hash = "sha256:b703fe72f8ce5b31ef031264fe9395cac8f46a04661a79f7ed31a80fb308730d", size = 20676, upload-time = "2026-01-07T03:20:52.929Z" }, + { url = "https://files.pythonhosted.org/packages/90/b8/78fd6c037de4788c040fdd323b3369804400351b7827473920f6c1d03c10/types_requests-2.33.0.20260408-py3-none-any.whl", hash = "sha256:81f31d5ea4acb39f03be7bc8bed569ba6d5a9c5d97e89f45ac43d819b68ca50f", size = 20739, upload-time = "2026-04-08T04:34:48.325Z" }, ] [[package]] name = "types-tqdm" -version = "4.67.3.20260303" +version = "4.67.3.20260408" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "types-requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/64/3e7cb0f40c4bf9578098b6873df33a96f7e0de90f3a039e614d22bfde40a/types_tqdm-4.67.3.20260303.tar.gz", hash = "sha256:7bfddb506a75aedb4030fabf4f05c5638c9a3bbdf900d54ec6c82be9034bfb96", size = 18117, upload-time = "2026-03-03T04:03:49.679Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/42/2e2968e68a694d3dac3a47aa0df06e46be1a6eef498e5bd15f4c54674eb9/types_tqdm-4.67.3.20260408.tar.gz", hash = "sha256:fd849a79891ae7136ed47541aface15c35bd9a13160fa8a93e42e10f60cf4c8d", size = 18119, upload-time = "2026-04-08T04:36:52.488Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/37/32/e4a1fce59155c74082f1a42d0ffafa59652bfb8cff35b04d56333877748e/types_tqdm-4.67.3.20260303-py3-none-any.whl", hash = "sha256:459decf677e4b05cef36f9012ef8d6e20578edefb6b78c15bd0b546247eda62d", size = 24572, upload-time = "2026-03-03T04:03:48.913Z" }, + { url = "https://files.pythonhosted.org/packages/14/5d/7dedddc32ab7bc2344ece772b5e0f03ec63a1d47ad259696689713c1cf50/types_tqdm-4.67.3.20260408-py3-none-any.whl", hash = "sha256:3b9ed74ebef04df8f53d470ffdc84348e93496d8acafa08bf79fafce0f2f5b5d", size = 24561, upload-time = "2026-04-08T04:36:51.538Z" }, ] [[package]] @@ -4484,63 +4837,68 @@ wheels = [ [[package]] name = "tzdata" -version = "2025.3" +version = "2026.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/f5/cd531b2d15a671a40c0f66cf06bc3570a12cd56eef98960068ebbad1bf5a/tzdata-2026.1.tar.gz", hash = "sha256:67658a1903c75917309e753fdc349ac0efd8c27db7a0cb406a25be4840f87f98", size = 197639, upload-time = "2026-04-03T11:25:22.002Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, + { url = "https://files.pythonhosted.org/packages/b0/70/d460bd685a170790ec89317e9bd33047988e4bce507b831f5db771e142de/tzdata-2026.1-py2.py3-none-any.whl", hash = "sha256:4b1d2be7ac37ceafd7327b961aa3a54e467efbdb563a23655fbfe0d39cfc42a9", size = 348952, upload-time = "2026-04-03T11:25:20.313Z" }, ] [[package]] name = "ujson" -version = "5.11.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/d9/3f17e3c5773fb4941c68d9a37a47b1a79c9649d6c56aefbed87cc409d18a/ujson-5.11.0.tar.gz", hash = "sha256:e204ae6f909f099ba6b6b942131cee359ddda2b6e4ea39c12eb8b991fe2010e0", size = 7156583, upload-time = "2025-08-20T11:57:02.452Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/ef/a9cb1fce38f699123ff012161599fb9f2ff3f8d482b4b18c43a2dc35073f/ujson-5.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7895f0d2d53bd6aea11743bd56e3cb82d729980636cd0ed9b89418bf66591702", size = 55434, upload-time = "2025-08-20T11:55:34.987Z" }, - { url = "https://files.pythonhosted.org/packages/b1/05/dba51a00eb30bd947791b173766cbed3492269c150a7771d2750000c965f/ujson-5.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12b5e7e22a1fe01058000d1b317d3b65cc3daf61bd2ea7a2b76721fe160fa74d", size = 53190, upload-time = "2025-08-20T11:55:36.384Z" }, - { url = "https://files.pythonhosted.org/packages/03/3c/fd11a224f73fbffa299fb9644e425f38b38b30231f7923a088dd513aabb4/ujson-5.11.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0180a480a7d099082501cad1fe85252e4d4bf926b40960fb3d9e87a3a6fbbc80", size = 57600, upload-time = "2025-08-20T11:55:37.692Z" }, - { url = "https://files.pythonhosted.org/packages/55/b9/405103cae24899df688a3431c776e00528bd4799e7d68820e7ebcf824f92/ujson-5.11.0-cp312-cp312-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:fa79fdb47701942c2132a9dd2297a1a85941d966d8c87bfd9e29b0cf423f26cc", size = 59791, upload-time = "2025-08-20T11:55:38.877Z" }, - { url = "https://files.pythonhosted.org/packages/17/7b/2dcbc2bbfdbf68f2368fb21ab0f6735e872290bb604c75f6e06b81edcb3f/ujson-5.11.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8254e858437c00f17cb72e7a644fc42dad0ebb21ea981b71df6e84b1072aaa7c", size = 57356, upload-time = "2025-08-20T11:55:40.036Z" }, - { url = "https://files.pythonhosted.org/packages/d1/71/fea2ca18986a366c750767b694430d5ded6b20b6985fddca72f74af38a4c/ujson-5.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1aa8a2ab482f09f6c10fba37112af5f957689a79ea598399c85009f2f29898b5", size = 1036313, upload-time = "2025-08-20T11:55:41.408Z" }, - { url = "https://files.pythonhosted.org/packages/a3/bb/d4220bd7532eac6288d8115db51710fa2d7d271250797b0bfba9f1e755af/ujson-5.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a638425d3c6eed0318df663df44480f4a40dc87cc7c6da44d221418312f6413b", size = 1195782, upload-time = "2025-08-20T11:55:43.357Z" }, - { url = "https://files.pythonhosted.org/packages/80/47/226e540aa38878ce1194454385701d82df538ccb5ff8db2cf1641dde849a/ujson-5.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7e3cff632c1d78023b15f7e3a81c3745cd3f94c044d1e8fa8efbd6b161997bbc", size = 1088817, upload-time = "2025-08-20T11:55:45.262Z" }, - { url = "https://files.pythonhosted.org/packages/7e/81/546042f0b23c9040d61d46ea5ca76f0cc5e0d399180ddfb2ae976ebff5b5/ujson-5.11.0-cp312-cp312-win32.whl", hash = "sha256:be6b0eaf92cae8cdee4d4c9e074bde43ef1c590ed5ba037ea26c9632fb479c88", size = 39757, upload-time = "2025-08-20T11:55:46.522Z" }, - { url = "https://files.pythonhosted.org/packages/44/1b/27c05dc8c9728f44875d74b5bfa948ce91f6c33349232619279f35c6e817/ujson-5.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:b7b136cc6abc7619124fd897ef75f8e63105298b5ca9bdf43ebd0e1fa0ee105f", size = 43859, upload-time = "2025-08-20T11:55:47.987Z" }, - { url = "https://files.pythonhosted.org/packages/22/2d/37b6557c97c3409c202c838aa9c960ca3896843b4295c4b7bb2bbd260664/ujson-5.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:6cd2df62f24c506a0ba322d5e4fe4466d47a9467b57e881ee15a31f7ecf68ff6", size = 38361, upload-time = "2025-08-20T11:55:49.122Z" }, - { url = "https://files.pythonhosted.org/packages/1c/ec/2de9dd371d52c377abc05d2b725645326c4562fc87296a8907c7bcdf2db7/ujson-5.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:109f59885041b14ee9569bf0bb3f98579c3fa0652317b355669939e5fc5ede53", size = 55435, upload-time = "2025-08-20T11:55:50.243Z" }, - { url = "https://files.pythonhosted.org/packages/5b/a4/f611f816eac3a581d8a4372f6967c3ed41eddbae4008d1d77f223f1a4e0a/ujson-5.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a31c6b8004438e8c20fc55ac1c0e07dad42941db24176fe9acf2815971f8e752", size = 53193, upload-time = "2025-08-20T11:55:51.373Z" }, - { url = "https://files.pythonhosted.org/packages/e9/c5/c161940967184de96f5cbbbcce45b562a4bf851d60f4c677704b1770136d/ujson-5.11.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78c684fb21255b9b90320ba7e199780f653e03f6c2528663768965f4126a5b50", size = 57603, upload-time = "2025-08-20T11:55:52.583Z" }, - { url = "https://files.pythonhosted.org/packages/2b/d6/c7b2444238f5b2e2d0e3dab300b9ddc3606e4b1f0e4bed5a48157cebc792/ujson-5.11.0-cp313-cp313-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:4c9f5d6a27d035dd90a146f7761c2272cf7103de5127c9ab9c4cd39ea61e878a", size = 59794, upload-time = "2025-08-20T11:55:53.69Z" }, - { url = "https://files.pythonhosted.org/packages/fe/a3/292551f936d3d02d9af148f53e1bc04306b00a7cf1fcbb86fa0d1c887242/ujson-5.11.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:837da4d27fed5fdc1b630bd18f519744b23a0b5ada1bbde1a36ba463f2900c03", size = 57363, upload-time = "2025-08-20T11:55:54.843Z" }, - { url = "https://files.pythonhosted.org/packages/90/a6/82cfa70448831b1a9e73f882225980b5c689bf539ec6400b31656a60ea46/ujson-5.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:787aff4a84da301b7f3bac09bc696e2e5670df829c6f8ecf39916b4e7e24e701", size = 1036311, upload-time = "2025-08-20T11:55:56.197Z" }, - { url = "https://files.pythonhosted.org/packages/84/5c/96e2266be50f21e9b27acaee8ca8f23ea0b85cb998c33d4f53147687839b/ujson-5.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:6dd703c3e86dc6f7044c5ac0b3ae079ed96bf297974598116aa5fb7f655c3a60", size = 1195783, upload-time = "2025-08-20T11:55:58.081Z" }, - { url = "https://files.pythonhosted.org/packages/8d/20/78abe3d808cf3bb3e76f71fca46cd208317bf461c905d79f0d26b9df20f1/ujson-5.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3772e4fe6b0c1e025ba3c50841a0ca4786825a4894c8411bf8d3afe3a8061328", size = 1088822, upload-time = "2025-08-20T11:55:59.469Z" }, - { url = "https://files.pythonhosted.org/packages/d8/50/8856e24bec5e2fc7f775d867aeb7a3f137359356200ac44658f1f2c834b2/ujson-5.11.0-cp313-cp313-win32.whl", hash = "sha256:8fa2af7c1459204b7a42e98263b069bd535ea0cd978b4d6982f35af5a04a4241", size = 39753, upload-time = "2025-08-20T11:56:01.345Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d8/1baee0f4179a4d0f5ce086832147b6cc9b7731c24ca08e14a3fdb8d39c32/ujson-5.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:34032aeca4510a7c7102bd5933f59a37f63891f30a0706fb46487ab6f0edf8f0", size = 43866, upload-time = "2025-08-20T11:56:02.552Z" }, - { url = "https://files.pythonhosted.org/packages/a9/8c/6d85ef5be82c6d66adced3ec5ef23353ed710a11f70b0b6a836878396334/ujson-5.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:ce076f2df2e1aa62b685086fbad67f2b1d3048369664b4cdccc50707325401f9", size = 38363, upload-time = "2025-08-20T11:56:03.688Z" }, - { url = "https://files.pythonhosted.org/packages/28/08/4518146f4984d112764b1dfa6fb7bad691c44a401adadaa5e23ccd930053/ujson-5.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:65724738c73645db88f70ba1f2e6fb678f913281804d5da2fd02c8c5839af302", size = 55462, upload-time = "2025-08-20T11:56:04.873Z" }, - { url = "https://files.pythonhosted.org/packages/29/37/2107b9a62168867a692654d8766b81bd2fd1e1ba13e2ec90555861e02b0c/ujson-5.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:29113c003ca33ab71b1b480bde952fbab2a0b6b03a4ee4c3d71687cdcbd1a29d", size = 53246, upload-time = "2025-08-20T11:56:06.054Z" }, - { url = "https://files.pythonhosted.org/packages/9b/f8/25583c70f83788edbe3ca62ce6c1b79eff465d78dec5eb2b2b56b3e98b33/ujson-5.11.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c44c703842024d796b4c78542a6fcd5c3cb948b9fc2a73ee65b9c86a22ee3638", size = 57631, upload-time = "2025-08-20T11:56:07.374Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ca/19b3a632933a09d696f10dc1b0dfa1d692e65ad507d12340116ce4f67967/ujson-5.11.0-cp314-cp314-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:e750c436fb90edf85585f5c62a35b35082502383840962c6983403d1bd96a02c", size = 59877, upload-time = "2025-08-20T11:56:08.534Z" }, - { url = "https://files.pythonhosted.org/packages/55/7a/4572af5324ad4b2bfdd2321e898a527050290147b4ea337a79a0e4e87ec7/ujson-5.11.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f278b31a7c52eb0947b2db55a5133fbc46b6f0ef49972cd1a80843b72e135aba", size = 57363, upload-time = "2025-08-20T11:56:09.758Z" }, - { url = "https://files.pythonhosted.org/packages/7b/71/a2b8c19cf4e1efe53cf439cdf7198ac60ae15471d2f1040b490c1f0f831f/ujson-5.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ab2cb8351d976e788669c8281465d44d4e94413718af497b4e7342d7b2f78018", size = 1036394, upload-time = "2025-08-20T11:56:11.168Z" }, - { url = "https://files.pythonhosted.org/packages/7a/3e/7b98668cba3bb3735929c31b999b374ebc02c19dfa98dfebaeeb5c8597ca/ujson-5.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:090b4d11b380ae25453100b722d0609d5051ffe98f80ec52853ccf8249dfd840", size = 1195837, upload-time = "2025-08-20T11:56:12.6Z" }, - { url = "https://files.pythonhosted.org/packages/a1/ea/8870f208c20b43571a5c409ebb2fe9b9dba5f494e9e60f9314ac01ea8f78/ujson-5.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:80017e870d882d5517d28995b62e4e518a894f932f1e242cbc802a2fd64d365c", size = 1088837, upload-time = "2025-08-20T11:56:14.15Z" }, - { url = "https://files.pythonhosted.org/packages/63/b6/c0e6607e37fa47929920a685a968c6b990a802dec65e9c5181e97845985d/ujson-5.11.0-cp314-cp314-win32.whl", hash = "sha256:1d663b96eb34c93392e9caae19c099ec4133ba21654b081956613327f0e973ac", size = 41022, upload-time = "2025-08-20T11:56:15.509Z" }, - { url = "https://files.pythonhosted.org/packages/4e/56/f4fe86b4c9000affd63e9219e59b222dc48b01c534533093e798bf617a7e/ujson-5.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:849e65b696f0d242833f1df4182096cedc50d414215d1371fca85c541fbff629", size = 45111, upload-time = "2025-08-20T11:56:16.597Z" }, - { url = "https://files.pythonhosted.org/packages/0a/f3/669437f0280308db4783b12a6d88c00730b394327d8334cc7a32ef218e64/ujson-5.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:e73df8648c9470af2b6a6bf5250d4744ad2cf3d774dcf8c6e31f018bdd04d764", size = 39682, upload-time = "2025-08-20T11:56:17.763Z" }, - { url = "https://files.pythonhosted.org/packages/6e/cd/e9809b064a89fe5c4184649adeb13c1b98652db3f8518980b04227358574/ujson-5.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:de6e88f62796372fba1de973c11138f197d3e0e1d80bcb2b8aae1e826096d433", size = 55759, upload-time = "2025-08-20T11:56:18.882Z" }, - { url = "https://files.pythonhosted.org/packages/1b/be/ae26a6321179ebbb3a2e2685b9007c71bcda41ad7a77bbbe164005e956fc/ujson-5.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:49e56ef8066f11b80d620985ae36869a3ff7e4b74c3b6129182ec5d1df0255f3", size = 53634, upload-time = "2025-08-20T11:56:20.012Z" }, - { url = "https://files.pythonhosted.org/packages/ae/e9/fb4a220ee6939db099f4cfeeae796ecb91e7584ad4d445d4ca7f994a9135/ujson-5.11.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1a325fd2c3a056cf6c8e023f74a0c478dd282a93141356ae7f16d5309f5ff823", size = 58547, upload-time = "2025-08-20T11:56:21.175Z" }, - { url = "https://files.pythonhosted.org/packages/bd/f8/fc4b952b8f5fea09ea3397a0bd0ad019e474b204cabcb947cead5d4d1ffc/ujson-5.11.0-cp314-cp314t-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:a0af6574fc1d9d53f4ff371f58c96673e6d988ed2b5bf666a6143c782fa007e9", size = 60489, upload-time = "2025-08-20T11:56:22.342Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e5/af5491dfda4f8b77e24cf3da68ee0d1552f99a13e5c622f4cef1380925c3/ujson-5.11.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10f29e71ecf4ecd93a6610bd8efa8e7b6467454a363c3d6416db65de883eb076", size = 58035, upload-time = "2025-08-20T11:56:23.92Z" }, - { url = "https://files.pythonhosted.org/packages/c4/09/0945349dd41f25cc8c38d78ace49f14c5052c5bbb7257d2f466fa7bdb533/ujson-5.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1a0a9b76a89827a592656fe12e000cf4f12da9692f51a841a4a07aa4c7ecc41c", size = 1037212, upload-time = "2025-08-20T11:56:25.274Z" }, - { url = "https://files.pythonhosted.org/packages/49/44/8e04496acb3d5a1cbee3a54828d9652f67a37523efa3d3b18a347339680a/ujson-5.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b16930f6a0753cdc7d637b33b4e8f10d5e351e1fb83872ba6375f1e87be39746", size = 1196500, upload-time = "2025-08-20T11:56:27.517Z" }, - { url = "https://files.pythonhosted.org/packages/64/ae/4bc825860d679a0f208a19af2f39206dfd804ace2403330fdc3170334a2f/ujson-5.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:04c41afc195fd477a59db3a84d5b83a871bd648ef371cf8c6f43072d89144eef", size = 1089487, upload-time = "2025-08-20T11:56:29.07Z" }, - { url = "https://files.pythonhosted.org/packages/30/ed/5a057199fb0a5deabe0957073a1c1c1c02a3e99476cd03daee98ea21fa57/ujson-5.11.0-cp314-cp314t-win32.whl", hash = "sha256:aa6d7a5e09217ff93234e050e3e380da62b084e26b9f2e277d2606406a2fc2e5", size = 41859, upload-time = "2025-08-20T11:56:30.495Z" }, - { url = "https://files.pythonhosted.org/packages/aa/03/b19c6176bdf1dc13ed84b886e99677a52764861b6cc023d5e7b6ebda249d/ujson-5.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:48055e1061c1bb1f79e75b4ac39e821f3f35a9b82de17fce92c3140149009bec", size = 46183, upload-time = "2025-08-20T11:56:31.574Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ca/a0413a3874b2dc1708b8796ca895bf363292f9c70b2e8ca482b7dbc0259d/ujson-5.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:1194b943e951092db611011cb8dbdb6cf94a3b816ed07906e14d3bc6ce0e90ab", size = 40264, upload-time = "2025-08-20T11:56:32.773Z" }, +version = "5.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cb/3e/c35530c5ffc25b71c59ae0cd7b8f99df37313daa162ce1e2f7925f7c2877/ujson-5.12.0.tar.gz", hash = "sha256:14b2e1eb528d77bc0f4c5bd1a7ebc05e02b5b41beefb7e8567c9675b8b13bcf4", size = 7158451, upload-time = "2026-03-11T22:19:30.397Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/f6/ac763d2108d28f3a40bb3ae7d2fafab52ca31b36c2908a4ad02cd3ceba2a/ujson-5.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:09b4beff9cc91d445d5818632907b85fb06943b61cb346919ce202668bf6794a", size = 56326, upload-time = "2026-03-11T22:18:18.467Z" }, + { url = "https://files.pythonhosted.org/packages/25/46/d0b3af64dcdc549f9996521c8be6d860ac843a18a190ffc8affeb7259687/ujson-5.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ca0c7ce828bb76ab78b3991904b477c2fd0f711d7815c252d1ef28ff9450b052", size = 53910, upload-time = "2026-03-11T22:18:19.502Z" }, + { url = "https://files.pythonhosted.org/packages/9a/10/853c723bcabc3e9825a079019055fc99e71b85c6bae600607a2b9d31d18d/ujson-5.12.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2d79c6635ccffcbfc1d5c045874ba36b594589be81d50d43472570bb8de9c57", size = 57754, upload-time = "2026-03-11T22:18:20.874Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c6/6e024830d988f521f144ead641981c1f7a82c17ad1927c22de3242565f5c/ujson-5.12.0-cp312-cp312-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:7e07f6f644d2c44d53b7a320a084eef98063651912c1b9449b5f45fcbdc6ccd2", size = 59936, upload-time = "2026-03-11T22:18:21.924Z" }, + { url = "https://files.pythonhosted.org/packages/34/c9/c5f236af5abe06b720b40b88819d00d10182d2247b1664e487b3ed9229cf/ujson-5.12.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:085b6ce182cdd6657481c7c4003a417e0655c4f6e58b76f26ee18f0ae21db827", size = 57463, upload-time = "2026-03-11T22:18:22.924Z" }, + { url = "https://files.pythonhosted.org/packages/ae/04/41342d9ef68e793a87d84e4531a150c2b682f3bcedfe59a7a5e3f73e9213/ujson-5.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:16b4fe9c97dc605f5e1887a9e1224287291e35c56cbc379f8aa44b6b7bcfe2bb", size = 1037239, upload-time = "2026-03-11T22:18:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/d4/81/dc2b7617d5812670d4ff4a42f6dd77926430ee52df0dedb2aec7990b2034/ujson-5.12.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0d2e8db5ade3736a163906154ca686203acc7d1d30736cbf577c730d13653d84", size = 1196713, upload-time = "2026-03-11T22:18:25.391Z" }, + { url = "https://files.pythonhosted.org/packages/b6/9c/80acff0504f92459ed69e80a176286e32ca0147ac6a8252cd0659aad3227/ujson-5.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:93bc91fdadcf046da37a214eaa714574e7e9b1913568e93bb09527b2ceb7f759", size = 1089742, upload-time = "2026-03-11T22:18:26.738Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f0/123ffaac17e45ef2b915e3e3303f8f4ea78bb8d42afad828844e08622b1e/ujson-5.12.0-cp312-cp312-win32.whl", hash = "sha256:2a248750abce1c76fbd11b2e1d88b95401e72819295c3b851ec73399d6849b3d", size = 39773, upload-time = "2026-03-11T22:18:28.244Z" }, + { url = "https://files.pythonhosted.org/packages/b5/20/f3bd2b069c242c2b22a69e033bfe224d1d15d3649e6cd7cc7085bb1412ff/ujson-5.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:1b5c6ceb65fecd28a1d20d1eba9dbfa992612b86594e4b6d47bb580d2dd6bcb3", size = 44040, upload-time = "2026-03-11T22:18:29.236Z" }, + { url = "https://files.pythonhosted.org/packages/f0/a7/01b5a0bcded14cd2522b218f2edc3533b0fcbccdea01f3e14a2b699071aa/ujson-5.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:9a5fcbe7b949f2e95c47ea8a80b410fcdf2da61c98553b45a4ee875580418b68", size = 38526, upload-time = "2026-03-11T22:18:30.551Z" }, + { url = "https://files.pythonhosted.org/packages/3f/f1/0ef0eeab1db8493e1833c8b440fe32cf7538f7afa6e7f7c7e9f62cef464d/ujson-5.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:15d416440148f3e56b9b244fdaf8a09fcf5a72e4944b8e119f5bf60417a2bfc8", size = 56331, upload-time = "2026-03-11T22:18:31.539Z" }, + { url = "https://files.pythonhosted.org/packages/b0/2f/9159f6f399b3f572d20847a2b80d133e3a03c14712b0da4971a36879fb64/ujson-5.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e0dd3676ea0837cd70ea1879765e9e9f6be063be0436de9b3ea4b775caf83654", size = 53910, upload-time = "2026-03-11T22:18:32.829Z" }, + { url = "https://files.pythonhosted.org/packages/e5/a9/f96376818d71495d1a4be19a0ab6acf0cc01dd8826553734c3d4dac685b2/ujson-5.12.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7bbf05c38debc90d1a195b11340cc85cb43ab3e753dc47558a3a84a38cbc72da", size = 57757, upload-time = "2026-03-11T22:18:33.866Z" }, + { url = "https://files.pythonhosted.org/packages/98/8d/dd4a151caac6fdcb77f024fbe7f09d465ebf347a628ed6dd581a0a7f6364/ujson-5.12.0-cp313-cp313-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:3c2f947e55d3c7cfe124dd4521ee481516f3007d13c6ad4bf6aeb722e190eb1b", size = 59940, upload-time = "2026-03-11T22:18:35.276Z" }, + { url = "https://files.pythonhosted.org/packages/c7/17/0d36c2fee0a8d8dc37b011ccd5bbdcfaff8b8ec2bcfc5be998661cdc935b/ujson-5.12.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ea6206043385343aff0b7da65cf73677f6f5e50de8f1c879e557f4298cac36a", size = 57465, upload-time = "2026-03-11T22:18:36.644Z" }, + { url = "https://files.pythonhosted.org/packages/8c/04/b0ee4a4b643a01ba398441da1e357480595edb37c6c94c508dbe0eb9eb60/ujson-5.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bb349dbba57c76eec25e5917e07f35aabaf0a33b9e67fc13d188002500106487", size = 1037236, upload-time = "2026-03-11T22:18:37.743Z" }, + { url = "https://files.pythonhosted.org/packages/2d/08/0e7780d0bbb48fe57ded91f550144bcc99c03b5360bf2886dd0dae0ea8f5/ujson-5.12.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:937794042342006f707837f38d721426b11b0774d327a2a45c0bd389eb750a87", size = 1196717, upload-time = "2026-03-11T22:18:39.101Z" }, + { url = "https://files.pythonhosted.org/packages/ba/4c/e0e34107715bb4dd2d4dcc1ce244d2f074638837adf38aff85a37506efe4/ujson-5.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6ad57654570464eb1b040b5c353dee442608e06cff9102b8fcb105565a44c9ed", size = 1089748, upload-time = "2026-03-11T22:18:40.473Z" }, + { url = "https://files.pythonhosted.org/packages/72/43/814f4e2b5374d0d505c254ba4bed43eb25d2d046f19f5fd88555f81a7bd0/ujson-5.12.0-cp313-cp313-win32.whl", hash = "sha256:76bf3e7406cf23a3e1ca6a23fb1fb9ea82f4f6bd226fe226e09146b0194f85dc", size = 39778, upload-time = "2026-03-11T22:18:41.791Z" }, + { url = "https://files.pythonhosted.org/packages/0f/fe/19310d848ebe93315b6cb171277e4ce29f47ef9d46caabd63ff05d5be548/ujson-5.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:15e555c4caca42411270b2ed2b2ebc7b3a42bb04138cef6c956e1f1d49709fe2", size = 44038, upload-time = "2026-03-11T22:18:43.094Z" }, + { url = "https://files.pythonhosted.org/packages/3f/e4/7a39103d7634691601a02bd1ca7268fba4da47ed586365e6ee68168f575a/ujson-5.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:bd03472c36fa3a386a6deb887113b9e3fa40efba8203eb4fe786d3c0ccc724f6", size = 38529, upload-time = "2026-03-11T22:18:44.167Z" }, + { url = "https://files.pythonhosted.org/packages/10/bd/9a8d693254bada62bfea75a507e014afcfdb6b9d047b6f8dd134bfefaf67/ujson-5.12.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:85833bca01aa5cae326ac759276dc175c5fa3f7b3733b7d543cf27f2df12d1ef", size = 56499, upload-time = "2026-03-11T22:18:45.431Z" }, + { url = "https://files.pythonhosted.org/packages/bd/2d/285a83df8176e18dcd675d1a4cff8f7620f003f30903ea43929406e98986/ujson-5.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d22cad98c2a10bbf6aa083a8980db6ed90d4285a841c4de892890c2b28286ef9", size = 53998, upload-time = "2026-03-11T22:18:47.184Z" }, + { url = "https://files.pythonhosted.org/packages/bf/8b/e2f09e16dabfa91f6a84555df34a4329fa7621e92ed054d170b9054b9bb2/ujson-5.12.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:99cc80facad240b0c2fb5a633044420878aac87a8e7c348b9486450cba93f27c", size = 57783, upload-time = "2026-03-11T22:18:48.271Z" }, + { url = "https://files.pythonhosted.org/packages/68/fb/ba1d06f3658a0c36d0ab3869ec3914f202bad0a9bde92654e41516c7bb13/ujson-5.12.0-cp314-cp314-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:d1831c07bd4dce53c4b666fa846c7eba4b7c414f2e641a4585b7f50b72f502dc", size = 60011, upload-time = "2026-03-11T22:18:49.284Z" }, + { url = "https://files.pythonhosted.org/packages/64/2b/3e322bf82d926d9857206cd5820438d78392d1f523dacecb8bd899952f73/ujson-5.12.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e00cec383eab2406c9e006bd4edb55d284e94bb943fda558326048178d26961", size = 57465, upload-time = "2026-03-11T22:18:50.584Z" }, + { url = "https://files.pythonhosted.org/packages/e9/fd/af72d69603f9885e5136509a529a4f6d88bf652b457263ff96aefcd3ab7d/ujson-5.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f19b3af31d02a2e79c5f9a6deaab0fb3c116456aeb9277d11720ad433de6dfc6", size = 1037275, upload-time = "2026-03-11T22:18:51.998Z" }, + { url = "https://files.pythonhosted.org/packages/9c/a7/a2411ec81aef7872578e56304c3e41b3a544a9809e95c8e1df46923fc40b/ujson-5.12.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:bacbd3c69862478cbe1c7ed4325caedec580d8acf31b8ee1b9a1e02a56295cad", size = 1196758, upload-time = "2026-03-11T22:18:53.548Z" }, + { url = "https://files.pythonhosted.org/packages/ed/85/aa18ae175dd03a118555aa14304d4f466f9db61b924c97c6f84388ecacb1/ujson-5.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94c5f1621cbcab83c03be46441f090b68b9f307b6c7ec44d4e3f6d5997383df4", size = 1089760, upload-time = "2026-03-11T22:18:55.336Z" }, + { url = "https://files.pythonhosted.org/packages/d3/d4/4b40b67ac7e916ebffc3041ae2320c5c0b8a045300d4c542b6e50930cca5/ujson-5.12.0-cp314-cp314-win32.whl", hash = "sha256:e6369ac293d2cc40d52577e4fa3d75a70c1aae2d01fa3580a34a4e6eff9286b9", size = 41043, upload-time = "2026-03-11T22:18:56.505Z" }, + { url = "https://files.pythonhosted.org/packages/24/38/a1496d2a3428981f2b3a2ffbb4656c2b05be6cc406301d6b10a6445f6481/ujson-5.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:31348a0ffbfc815ce78daac569d893349d85a0b57e1cd2cdbba50b7f333784da", size = 45303, upload-time = "2026-03-11T22:18:57.454Z" }, + { url = "https://files.pythonhosted.org/packages/85/d3/39dbd3159543d9c57ec3a82d36226152cf0d710784894ce5aa24b8220ac1/ujson-5.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:6879aed770557f0961b252648d36f6fdaab41079d37a2296b5649fd1b35608e0", size = 39860, upload-time = "2026-03-11T22:18:58.578Z" }, + { url = "https://files.pythonhosted.org/packages/c3/71/9b4dacb177d3509077e50497222d39eec04c8b41edb1471efc764d645237/ujson-5.12.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7ddb08b3c2f9213df1f2e3eb2fbea4963d80ec0f8de21f0b59898e34f3b3d96d", size = 56845, upload-time = "2026-03-11T22:18:59.629Z" }, + { url = "https://files.pythonhosted.org/packages/24/c2/8abffa3be1f3d605c4a62445fab232b3e7681512ce941c6b23014f404d36/ujson-5.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0a3ae28f0b209be5af50b54ca3e2123a3de3a57d87b75f1e5aa3d7961e041983", size = 54463, upload-time = "2026-03-11T22:19:00.697Z" }, + { url = "https://files.pythonhosted.org/packages/db/2e/60114a35d1d6796eb428f7affcba00a921831ff604a37d9142c3d8bbe5c5/ujson-5.12.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d30ad4359413c8821cc7b3707f7ca38aa8bc852ba3b9c5a759ee2d7740157315", size = 58689, upload-time = "2026-03-11T22:19:01.739Z" }, + { url = "https://files.pythonhosted.org/packages/c8/ad/010925c2116c21ce119f9c2ff18d01f48a19ade3ff4c5795da03ce5829fc/ujson-5.12.0-cp314-cp314t-manylinux_2_24_i686.manylinux_2_28_i686.whl", hash = "sha256:02f93da7a4115e24f886b04fd56df1ee8741c2ce4ea491b7ab3152f744ad8f8e", size = 60618, upload-time = "2026-03-11T22:19:03.101Z" }, + { url = "https://files.pythonhosted.org/packages/9b/74/db7f638bf20282b1dccf454386cbd483faaaed3cdbb9cb27e06f74bb109e/ujson-5.12.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3ff4ede90ed771140caa7e1890de17431763a483c54b3c1f88bd30f0cc1affc0", size = 58151, upload-time = "2026-03-11T22:19:04.175Z" }, + { url = "https://files.pythonhosted.org/packages/9c/7e/3ebaecfa70a2e8ce623db8e21bd5cb05d42a5ef943bcbb3309d71b5de68d/ujson-5.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bf9cc97f05048ac8f3e02cd58f0fe62b901453c24345bfde287f4305dcc31c", size = 1038117, upload-time = "2026-03-11T22:19:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/2e/aa/e073eda7f0036c2973b28db7bb99faba17a932e7b52d801f9bb3e726271f/ujson-5.12.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:2324d9a0502317ffc35d38e153c1b2fa9610ae03775c9d0f8d0cca7b8572b04e", size = 1197434, upload-time = "2026-03-11T22:19:06.92Z" }, + { url = "https://files.pythonhosted.org/packages/1c/01/b9a13f058fdd50c746b192c4447ca8d6352e696dcda912ccee10f032ff85/ujson-5.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:50524f4f6a1c839714dbaff5386a1afb245d2d5ec8213a01fbc99cea7307811e", size = 1090401, upload-time = "2026-03-11T22:19:08.383Z" }, + { url = "https://files.pythonhosted.org/packages/c4/37/3d1b4e0076b6e43379600b5229a5993db8a759ff2e1830ea635d876f6644/ujson-5.12.0-cp314-cp314t-win32.whl", hash = "sha256:f7a0430d765f9bda043e6aefaba5944d5f21ec43ff4774417d7e296f61917382", size = 41880, upload-time = "2026-03-11T22:19:09.671Z" }, + { url = "https://files.pythonhosted.org/packages/b1/c5/3c2a262a138b9f0014fe1134a6b5fdc2c54245030affbaac2fcbc0632138/ujson-5.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:ccbfd94e59aad4a2566c71912b55f0547ac1680bfac25eb138e6703eb3dd434e", size = 46365, upload-time = "2026-03-11T22:19:10.662Z" }, + { url = "https://files.pythonhosted.org/packages/83/40/956dc20b7e00dc0ff3259871864f18dab211837fce3478778bedb3132ac1/ujson-5.12.0-cp314-cp314t-win_arm64.whl", hash = "sha256:42d875388fbd091c7ea01edfff260f839ba303038ffb23475ef392012e4d63dd", size = 40398, upload-time = "2026-03-11T22:19:11.666Z" }, + { url = "https://files.pythonhosted.org/packages/95/3c/5ee154d505d1aad2debc4ba38b1a60ae1949b26cdb5fa070e85e320d6b64/ujson-5.12.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:bf85a00ac3b56a1e7a19c5be7b02b5180a0895ac4d3c234d717a55e86960691c", size = 54494, upload-time = "2026-03-11T22:19:13.035Z" }, + { url = "https://files.pythonhosted.org/packages/ce/b3/9496ec399ec921e434a93b340bd5052999030b7ac364be4cbe5365ac6b20/ujson-5.12.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:64df53eef4ac857eb5816a56e2885ccf0d7dff6333c94065c93b39c51063e01d", size = 57999, upload-time = "2026-03-11T22:19:14.385Z" }, + { url = "https://files.pythonhosted.org/packages/0e/da/e9ae98133336e7c0d50b43626c3f2327937cecfa354d844e02ac17379ed1/ujson-5.12.0-graalpy312-graalpy250_312_native-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c0aed6a4439994c9666fb8a5b6c4eac94d4ef6ddc95f9b806a599ef83547e3b", size = 54518, upload-time = "2026-03-11T22:19:15.4Z" }, + { url = "https://files.pythonhosted.org/packages/58/10/978d89dded6bb1558cd46ba78f4351198bd2346db8a8ee1a94119022ce40/ujson-5.12.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:efae5df7a8cc8bdb1037b0f786b044ce281081441df5418c3a0f0e1f86fe7bb3", size = 55736, upload-time = "2026-03-11T22:19:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/80/25/1df8e6217c92e57a1266bf5be750b1dddc126ee96e53fe959d5693503bc6/ujson-5.12.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:8712b61eb1b74a4478cfd1c54f576056199e9f093659334aeb5c4a6b385338e5", size = 44615, upload-time = "2026-03-11T22:19:17.53Z" }, ] [[package]] @@ -4553,48 +4911,12 @@ wheels = [ ] [[package]] -name = "websockets" -version = "16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" }, - { url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" }, - { url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" }, - { url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" }, - { url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" }, - { url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" }, - { url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" }, - { url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" }, - { url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" }, - { url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" }, - { url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" }, - { url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" }, - { url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" }, - { url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" }, - { url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" }, - { url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" }, - { url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" }, - { url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" }, - { url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" }, - { url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" }, - { url = "https://files.pythonhosted.org/packages/63/bc/d3e208028de777087e6fb2b122051a6ff7bbcca0d6df9d9c2bf1dd869ae9/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e", size = 185044, upload-time = "2026-01-10T09:23:15.939Z" }, - { url = "https://files.pythonhosted.org/packages/ad/6e/9a0927ac24bd33a0a9af834d89e0abc7cfd8e13bed17a86407a66773cc0e/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4", size = 186279, upload-time = "2026-01-10T09:23:17.148Z" }, - { url = "https://files.pythonhosted.org/packages/b9/ca/bf1c68440d7a868180e11be653c85959502efd3a709323230314fda6e0b3/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1", size = 185711, upload-time = "2026-01-10T09:23:18.372Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f8/fdc34643a989561f217bb477cbc47a3a07212cbda91c0e4389c43c296ebf/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3", size = 184982, upload-time = "2026-01-10T09:23:19.652Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d1/574fa27e233764dbac9c52730d63fcf2823b16f0856b3329fc6268d6ae4f/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8", size = 177915, upload-time = "2026-01-10T09:23:21.458Z" }, - { url = "https://files.pythonhosted.org/packages/8a/f1/ae6b937bf3126b5134ce1f482365fde31a357c784ac51852978768b5eff4/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d", size = 178381, upload-time = "2026-01-10T09:23:22.715Z" }, - { url = "https://files.pythonhosted.org/packages/06/9b/f791d1db48403e1f0a27577a6beb37afae94254a8c6f08be4a23e4930bc0/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244", size = 177737, upload-time = "2026-01-10T09:23:24.523Z" }, - { url = "https://files.pythonhosted.org/packages/bd/40/53ad02341fa33b3ce489023f635367a4ac98b73570102ad2cdd770dacc9a/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e", size = 175268, upload-time = "2026-01-10T09:23:25.781Z" }, - { url = "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641", size = 175486, upload-time = "2026-01-10T09:23:27.033Z" }, - { url = "https://files.pythonhosted.org/packages/e5/2d/7583b30208b639c8090206f95073646c2c9ffd66f44df967981a64f849ad/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8", size = 185331, upload-time = "2026-01-10T09:23:28.259Z" }, - { url = "https://files.pythonhosted.org/packages/45/b0/cce3784eb519b7b5ad680d14b9673a31ab8dcb7aad8b64d81709d2430aa8/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e", size = 186501, upload-time = "2026-01-10T09:23:29.449Z" }, - { url = "https://files.pythonhosted.org/packages/19/60/b8ebe4c7e89fb5f6cdf080623c9d92789a53636950f7abacfc33fe2b3135/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944", size = 186062, upload-time = "2026-01-10T09:23:31.368Z" }, - { url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" }, - { url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" }, - { url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" }, - { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, +name = "websocket-client" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, ] [[package]] @@ -4609,24 +4931,45 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/87/22/b76d483683216dde3d67cba61fb2444be8d5be289bf628c13fc0fd90e5f9/wheel-0.46.3-py3-none-any.whl", hash = "sha256:4b399d56c9d9338230118d705d9737a2a468ccca63d5e813e2a4fc7815d8bc4d", size = 30557, upload-time = "2026-01-22T12:39:48.099Z" }, ] +[[package]] +name = "wxpython" +version = "4.1.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and sys_platform == 'darwin'", + "python_full_version == '3.13.*' and sys_platform == 'darwin'", + "python_full_version < '3.13' and sys_platform == 'darwin'", +] +dependencies = [ + { name = "numpy", marker = "sys_platform == 'darwin'" }, + { name = "pillow", marker = "sys_platform == 'darwin'" }, + { name = "six", marker = "sys_platform == 'darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b0/4d/80d65c37ee60a479d338d27a2895fb15bbba27a3e6bb5b6d72bb28246e99/wxPython-4.1.1.tar.gz", hash = "sha256:00e5e3180ac7f2852f342ad341d57c44e7e4326de0b550b9a5c4a8361b6c3528", size = 66043287, upload-time = "2020-11-25T21:50:16.721Z" } + [[package]] name = "wxpython" version = "4.2.5" source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and sys_platform == 'win32'", + "python_full_version >= '3.14' and sys_platform == 'emscripten'", + "python_full_version >= '3.14' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'win32'", + "python_full_version < '3.13' and sys_platform == 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'emscripten'", + "python_full_version < '3.13' and sys_platform == 'emscripten'", + "python_full_version == '3.13.*' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", + "python_full_version < '3.13' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", +] sdist = { url = "https://files.pythonhosted.org/packages/22/43/81657a6b126ffc19163500a8184d683cec08eb4e1d06905cd0c371c702d0/wxpython-4.2.5.tar.gz", hash = "sha256:44e836d1bccd99c38790bb034b6ecf70d9060f6734320560f7c4b0d006144793", size = 58732217, upload-time = "2026-02-08T20:40:42.086Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/b7/aa689ba41312a94079e692f7a5a5c0bd1c6086bc929c9eb13f3b5c6bda58/wxpython-4.2.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:310772b05372c2daa76fefa7e57d20106b522d53b49d3edc3d9ac1fde7e3782e", size = 17774402, upload-time = "2026-02-08T20:39:57.348Z" }, - { url = "https://files.pythonhosted.org/packages/21/66/4ea97c2b6e8e627e645b3a8a2f6e4d5db3c1799845d730fd3df91b5ac294/wxpython-4.2.5-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:10bba0d56547f34d12b5450e8c73e32ff821aed10a2f34a0c666c8355eb9ee98", size = 18855177, upload-time = "2026-02-08T20:40:00.588Z" }, { url = "https://files.pythonhosted.org/packages/5d/3a/5136bf39877640c8a254f1370279943366d04d321461a450fcef53722f38/wxpython-4.2.5-cp312-cp312-win32.whl", hash = "sha256:e7079d9a7374b3fd5896bdea7c73faa8da52e1fbcce5368796b5c22d7de747a6", size = 14519633, upload-time = "2026-02-08T20:40:03.577Z" }, { url = "https://files.pythonhosted.org/packages/99/5d/2c2c9dbf78f9524daf79014337e193531332c3598b16ccc11290dad9c17f/wxpython-4.2.5-cp312-cp312-win_amd64.whl", hash = "sha256:c54962f0524662d16591a03c786cd4d71bc43c70ede8244e0a5a59aa3979d124", size = 16577057, upload-time = "2026-02-08T20:40:06.002Z" }, { url = "https://files.pythonhosted.org/packages/b4/10/a7ed092d0426cc98ab1a907c9e6161d8846e0de0450447b877048a8ef4e3/wxpython-4.2.5-cp312-cp312-win_arm64.whl", hash = "sha256:cda1fb351caa4555bd18717f610c9a3b03d25e64db4a22e004b141f91d02fa8c", size = 15537110, upload-time = "2026-02-08T20:40:09.022Z" }, - { url = "https://files.pythonhosted.org/packages/e4/b9/1fee711ad5c26e7bbd4e10fae14b2ce0499684a084c3c60169373496ceae/wxpython-4.2.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5f7ec6b028e8b1c4cad1ecb5c8402c2cae7840a25758be0fc209e56df86d1cac", size = 17775906, upload-time = "2026-02-08T20:40:12.031Z" }, - { url = "https://files.pythonhosted.org/packages/3d/53/521a79cbb169ab6b123e79ea23ebafe3046c1999a431b6fc864f1217bb86/wxpython-4.2.5-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:77ac5335d8e4aae92732fc039df24a58181cdfb5bc7931692f1f9415e9eeee7d", size = 18857767, upload-time = "2026-02-08T20:40:14.486Z" }, { url = "https://files.pythonhosted.org/packages/c4/ea/a69ad0a1e7b01876619982b6cf8db0e26d0f3776b9be73b61d9f0662a2ce/wxpython-4.2.5-cp313-cp313-win32.whl", hash = "sha256:0985f190565b94635f146989886196a7e9faced8911800910460919cb72668cc", size = 14520419, upload-time = "2026-02-08T20:40:17.401Z" }, { url = "https://files.pythonhosted.org/packages/a8/bd/d2698369dbc43aa5c9324c23fdd5cd3b23c245861e334b1d976209913f90/wxpython-4.2.5-cp313-cp313-win_amd64.whl", hash = "sha256:3fd3649fc4752f1a02776b7057073c932e5229bbab2031762b01532bcc6bd074", size = 16576741, upload-time = "2026-02-08T20:40:20.646Z" }, { url = "https://files.pythonhosted.org/packages/cb/4e/4181734a2bc05940ba4feb3feb2474416b1dc12c329a2ac164632582c4d6/wxpython-4.2.5-cp313-cp313-win_arm64.whl", hash = "sha256:b794d9912464990ea1fd3744fb73fbd7446149e230e5a611ba40eb4ac74755a1", size = 15537287, upload-time = "2026-02-08T20:40:24.658Z" }, - { url = "https://files.pythonhosted.org/packages/e5/a1/9d8a7c5f60bb311257b04e3a3d9bbf12e4ab1fcc92811a007bbdf43b1e5f/wxpython-4.2.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:af2d8388eb3f0d8eaae0713a35c307293435ec279f215a2bbf521b738d7fc91b", size = 17783876, upload-time = "2026-02-08T20:40:27.739Z" }, - { url = "https://files.pythonhosted.org/packages/e9/9c/32862d321db8927f37d2572e606cf480e013942e5c6ce39fef37c4a713cb/wxpython-4.2.5-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:1925485c9b90e79f869272eff2b99438538b00505f9d148d51358dc8e92116b6", size = 18864211, upload-time = "2026-02-08T20:40:30.523Z" }, { url = "https://files.pythonhosted.org/packages/51/a7/261bf54686192ebefc42b494da97ba3312bd01c1d37a964f0cb83f271cf0/wxpython-4.2.5-cp314-cp314-win32.whl", hash = "sha256:230ecb4de65a8d2f8bc30bccd4d64366ac3a7cf53759b77920de927d156ad9c5", size = 14859697, upload-time = "2026-02-08T20:40:33.108Z" }, { url = "https://files.pythonhosted.org/packages/fd/9a/73f12041178db3728a809ce37c2b64409291cb45567b2918df478f0ceb20/wxpython-4.2.5-cp314-cp314-win_amd64.whl", hash = "sha256:eb1c228f0c20ed93f2799ebd81780abc7fd65cfa8f6b65e989b68c0c18c52707", size = 16947346, upload-time = "2026-02-08T20:40:35.583Z" }, { url = "https://files.pythonhosted.org/packages/b6/49/3a39f5fe78a7194c848919c4b681f432fe937006e2e5182a17dd519f8c91/wxpython-4.2.5-cp314-cp314-win_arm64.whl", hash = "sha256:d4439bf4b18ac720afbcf51c37d7822ba62ab6999501e96cce1dfc2f55a19344", size = 15809574, upload-time = "2026-02-08T20:40:38.859Z" }, @@ -4634,47 +4977,25 @@ wheels = [ [[package]] name = "xarray" -version = "2026.2.0" +version = "2026.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "packaging" }, { name = "pandas" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0f/03/e3353b72e518574b32993989d8f696277bf878e9d508c7dd22e86c0dab5b/xarray-2026.2.0.tar.gz", hash = "sha256:978b6acb018770554f8fd964af4eb02f9bcc165d4085dbb7326190d92aa74bcf", size = 3111388, upload-time = "2026-02-13T22:20:50.18Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/a6/6fe936a798a3a38a79c7422d1a31afd2e9a14690fcb0ccff96bc01f04bf2/xarray-2026.4.0.tar.gz", hash = "sha256:c4ac9a01a945d90d5b1628e2af045099a9d4943536d4f2ee3ae963c3b222d15b", size = 3132311, upload-time = "2026-04-13T19:45:36.688Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/99/92/545eb2ca17fc0e05456728d7e4378bfee48d66433ae3b7e71948e46826fb/xarray-2026.2.0-py3-none-any.whl", hash = "sha256:e927d7d716ea71dea78a13417970850a640447d8dd2ceeb65c5687f6373837c9", size = 1405358, upload-time = "2026-02-13T22:20:47.847Z" }, + { url = "https://files.pythonhosted.org/packages/dc/83/6d810a8a9ebc9c307989b418840c20e46907c74d707beb67ab566773e6fc/xarray-2026.4.0-py3-none-any.whl", hash = "sha256:d43751d9fb4a90f9249c30431684f00c41bc874f1edccd862631a40cbc0edf08", size = 1414326, upload-time = "2026-04-13T19:45:34.659Z" }, ] [[package]] -name = "xmlschema" -version = "4.3.1" +name = "xlrd" +version = "2.0.2" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "elementpath" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/da/c4/ef78a231be72349fd6677b989ff80e276ef62e28054c36c4fea3b4db9611/xmlschema-4.3.1.tar.gz", hash = "sha256:853effdfaf127849d4724368c17bd669e7f1486e15a0376404ad7954ec31a338", size = 646611, upload-time = "2026-01-17T23:01:04.422Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/7b/3471405875d0b5fac642e9a879b2c7db63642370799b2e9eea8297ffbad0/xmlschema-4.3.1-py3-none-any.whl", hash = "sha256:9560314d70ae87be0aecb8712cfebed636f867707ccf9758d4b0645d607f64b9", size = 469891, upload-time = "2026-01-17T23:01:00.39Z" }, -] - -[[package]] -name = "zeroconf" -version = "0.148.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ifaddr", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/67/46/10db987799629d01930176ae523f70879b63577060d63e05ebf9214aba4b/zeroconf-0.148.0.tar.gz", hash = "sha256:03fcca123df3652e23d945112d683d2f605f313637611b7d4adf31056f681702", size = 164447, upload-time = "2025-10-05T00:21:19.199Z" } +sdist = { url = "https://files.pythonhosted.org/packages/07/5a/377161c2d3538d1990d7af382c79f3b2372e880b65de21b01b1a2b78691e/xlrd-2.0.2.tar.gz", hash = "sha256:08b5e25de58f21ce71dc7db3b3b8106c1fa776f3024c54e45b45b374e89234c9", size = 100167, upload-time = "2025-06-14T08:46:39.039Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/b3/6c08ccbda1e78c8f538d8add49fac2fe49ef85ee34b62877df4154715583/zeroconf-0.148.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aef8699ea47cd47c9219e3f110a35ad50c13c34c7c6db992f3c9f75feec6ef8f", size = 1735431, upload-time = "2025-10-05T01:08:09.375Z" }, - { url = "https://files.pythonhosted.org/packages/cb/37/6b91c4a4258863e485602e6b1eb098fe406142a653112e8719c49b69afc4/zeroconf-0.148.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9097e7010b9f9a64e5f2084493e9973d446bd85c7a7cbef5032b2b0a2ecc5a12", size = 1701594, upload-time = "2025-10-05T01:08:11.448Z" }, - { url = "https://files.pythonhosted.org/packages/46/09/394a24a633645063557c5144c9abb694699df76155dcab5e1e3078dd1323/zeroconf-0.148.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ad889929bdc3953530546a4a2486d8c07f5a18d4ef494a98446bf17414897a7", size = 1714465, upload-time = "2025-10-05T01:08:28.692Z" }, - { url = "https://files.pythonhosted.org/packages/3d/db/f57c4bfcceb67fe474705cbadba3f8f7a88bdc95892e74ba6d85e24d28c3/zeroconf-0.148.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:29fb10be743650eb40863f1a1ee868df1869357a0c2ab75140ee3d7079540c1e", size = 1683877, upload-time = "2025-10-05T01:08:30.42Z" }, - { url = "https://files.pythonhosted.org/packages/a5/46/ac86e3a3ff355058cd0818b01a3a97ca3f2abc0a034f1edb8eea27cea65c/zeroconf-0.148.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:2158d8bfefcdb90237937df65b2235870ccef04644497e4e29d3ab5a4b3199b6", size = 1714870, upload-time = "2025-10-05T01:08:47.624Z" }, - { url = "https://files.pythonhosted.org/packages/de/02/c5e8cd8dfda0ca16c7309c8d12c09a3114e5b50054bce3c93da65db8b8e4/zeroconf-0.148.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:695f6663bf8df30fe1826a2c4d5acd8213d9cbd9111f59d375bf1ad635790e98", size = 1697756, upload-time = "2025-10-05T01:08:49.472Z" }, - { url = "https://files.pythonhosted.org/packages/36/fb/53d749793689279bc9657d818615176577233ad556d62f76f719e86ead1d/zeroconf-0.148.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:40fe100381365c983a89e4b219a7ececcc2a789ac179cd26d4a6bbe00ae3e8fe", size = 3418152, upload-time = "2025-10-05T01:09:06.71Z" }, - { url = "https://files.pythonhosted.org/packages/b9/19/5eb647f7277378cbfdb6943dc8e60c3b17cdd1556f5082ccfdd6813e1ce8/zeroconf-0.148.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0b9c7bcae8af8e27593bad76ee0f0c21d43c6a2324cd1e34d06e6e08cb3fd922", size = 3389671, upload-time = "2025-10-05T01:09:08.903Z" }, + { url = "https://files.pythonhosted.org/packages/1a/62/c8d562e7766786ba6587d09c5a8ba9f718ed3fa8af7f4553e8f91c36f302/xlrd-2.0.2-py2.py3-none-any.whl", hash = "sha256:ea762c3d29f4cca48d82df517b6d89fbce4db3107f9d78713e48cd321d5c9aa9", size = 96555, upload-time = "2025-06-14T08:46:37.766Z" }, ] [[package]] @@ -4688,26 +5009,26 @@ wheels = [ [[package]] name = "zope-interface" -version = "8.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/86/a4/77daa5ba398996d16bb43fc721599d27d03eae68fe3c799de1963c72e228/zope_interface-8.2.tar.gz", hash = "sha256:afb20c371a601d261b4f6edb53c3c418c249db1a9717b0baafc9a9bb39ba1224", size = 254019, upload-time = "2026-01-09T07:51:07.253Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/a0/1e1fabbd2e9c53ef92b69df6d14f4adc94ec25583b1380336905dc37e9a0/zope_interface-8.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:624b6787fc7c3e45fa401984f6add2c736b70a7506518c3b537ffaacc4b29d4c", size = 208785, upload-time = "2026-01-09T08:05:17.348Z" }, - { url = "https://files.pythonhosted.org/packages/c3/2a/88d098a06975c722a192ef1fb7d623d1b57c6a6997cf01a7aabb45ab1970/zope_interface-8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bc9ded9e97a0ed17731d479596ed1071e53b18e6fdb2fc33af1e43f5fd2d3aaa", size = 208976, upload-time = "2026-01-09T08:05:18.792Z" }, - { url = "https://files.pythonhosted.org/packages/e9/e8/757398549fdfd2f8c89f32c82ae4d2f0537ae2a5d2f21f4a2f711f5a059f/zope_interface-8.2-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:532367553e4420c80c0fc0cabcc2c74080d495573706f66723edee6eae53361d", size = 259411, upload-time = "2026-01-09T08:05:20.567Z" }, - { url = "https://files.pythonhosted.org/packages/91/af/502601f0395ce84dff622f63cab47488657a04d0065547df42bee3a680ff/zope_interface-8.2-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2bf9cf275468bafa3c72688aad8cfcbe3d28ee792baf0b228a1b2d93bd1d541a", size = 264859, upload-time = "2026-01-09T08:05:22.234Z" }, - { url = "https://files.pythonhosted.org/packages/89/0c/d2f765b9b4814a368a7c1b0ac23b68823c6789a732112668072fe596945d/zope_interface-8.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0009d2d3c02ea783045d7804da4fd016245e5c5de31a86cebba66dd6914d59a2", size = 264398, upload-time = "2026-01-09T08:05:23.853Z" }, - { url = "https://files.pythonhosted.org/packages/4a/81/2f171fbc4222066957e6b9220c4fb9146792540102c37e6d94e5d14aad97/zope_interface-8.2-cp312-cp312-win_amd64.whl", hash = "sha256:845d14e580220ae4544bd4d7eb800f0b6034fe5585fc2536806e0a26c2ee6640", size = 212444, upload-time = "2026-01-09T08:05:25.148Z" }, - { url = "https://files.pythonhosted.org/packages/66/47/45188fb101fa060b20e6090e500682398ab415e516a0c228fbb22bc7def2/zope_interface-8.2-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:6068322004a0158c80dfd4708dfb103a899635408c67c3b10e9acec4dbacefec", size = 209170, upload-time = "2026-01-09T08:05:26.616Z" }, - { url = "https://files.pythonhosted.org/packages/09/03/f6b9336c03c2b48403c4eb73a1ec961d94dc2fb5354c583dfb5fa05fd41f/zope_interface-8.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2499de92e8275d0dd68f84425b3e19e9268cd1fa8507997900fa4175f157733c", size = 209229, upload-time = "2026-01-09T08:05:28.521Z" }, - { url = "https://files.pythonhosted.org/packages/07/b1/65fe1dca708569f302ade02e6cdca309eab6752bc9f80105514f5b708651/zope_interface-8.2-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f777e68c76208503609c83ca021a6864902b646530a1a39abb9ed310d1100664", size = 259393, upload-time = "2026-01-09T08:05:29.897Z" }, - { url = "https://files.pythonhosted.org/packages/eb/a5/97b49cfceb6ed53d3dcfb3f3ebf24d83b5553194f0337fbbb3a9fec6cf78/zope_interface-8.2-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b05a919fdb0ed6ea942e5a7800e09a8b6cdae6f98fee1bef1c9d1a3fc43aaa0", size = 264863, upload-time = "2026-01-09T08:05:31.501Z" }, - { url = "https://files.pythonhosted.org/packages/cb/02/0b7a77292810efe3a0586a505b077ebafd5114e10c6e6e659f0c8e387e1f/zope_interface-8.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ccc62b5712dd7bd64cfba3ee63089fb11e840f5914b990033beeae3b2180b6cb", size = 264369, upload-time = "2026-01-09T08:05:32.941Z" }, - { url = "https://files.pythonhosted.org/packages/fb/1d/0d1ff3846302ed1b5bbf659316d8084b30106770a5f346b7ff4e9f540f80/zope_interface-8.2-cp313-cp313-win_amd64.whl", hash = "sha256:34f877d1d3bb7565c494ed93828fa6417641ca26faf6e8f044e0d0d500807028", size = 212447, upload-time = "2026-01-09T08:05:35.064Z" }, - { url = "https://files.pythonhosted.org/packages/1a/da/3c89de3917751446728b8898b4d53318bc2f8f6bf8196e150a063c59905e/zope_interface-8.2-cp314-cp314-macosx_10_9_x86_64.whl", hash = "sha256:46c7e4e8cbc698398a67e56ca985d19cb92365b4aafbeb6a712e8c101090f4cb", size = 209223, upload-time = "2026-01-09T08:05:36.449Z" }, - { url = "https://files.pythonhosted.org/packages/00/7f/62d00ec53f0a6e5df0c984781e6f3999ed265129c4c3413df8128d1e0207/zope_interface-8.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a87fc7517f825a97ff4a4ca4c8a950593c59e0f8e7bfe1b6f898a38d5ba9f9cf", size = 209366, upload-time = "2026-01-09T08:05:38.197Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a2/f241986315174be8e00aabecfc2153cf8029c1327cab8ed53a9d979d7e08/zope_interface-8.2-cp314-cp314-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:ccf52f7d44d669203c2096c1a0c2c15d52e36b2e7a9413df50f48392c7d4d080", size = 261037, upload-time = "2026-01-09T08:05:39.568Z" }, - { url = "https://files.pythonhosted.org/packages/02/cc/b321c51d6936ede296a1b8860cf173bee2928357fe1fff7f97234899173f/zope_interface-8.2-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:aae807efc7bd26302eb2fea05cd6de7d59269ed6ae23a6de1ee47add6de99b8c", size = 264219, upload-time = "2026-01-09T08:05:41.624Z" }, - { url = "https://files.pythonhosted.org/packages/ab/fb/5f5e7b40a2f4efd873fe173624795ca47eaa22e29051270c981361b45209/zope_interface-8.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:05a0e42d6d830f547e114de2e7cd15750dc6c0c78f8138e6c5035e51ddfff37c", size = 264390, upload-time = "2026-01-09T08:05:42.936Z" }, - { url = "https://files.pythonhosted.org/packages/f9/82/3f2bc594370bc3abd58e5f9085d263bf682a222f059ed46275cde0570810/zope_interface-8.2-cp314-cp314-win_amd64.whl", hash = "sha256:561ce42390bee90bae51cf1c012902a8033b2aaefbd0deed81e877562a116d48", size = 212585, upload-time = "2026-01-09T08:05:44.419Z" }, +version = "8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/04/0b1d92e7d31507c5fbe203d9cc1ae80fb0645688c7af751ea0ec18c2223e/zope_interface-8.3.tar.gz", hash = "sha256:e1a9de7d0b5b5c249a73b91aebf4598ce05e334303af6aa94865893283e9ff10", size = 256822, upload-time = "2026-04-10T06:12:35.036Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/1e/7ed593f9c3664e560febe1f132fdf73b8bb9a3de6e3448093b0167239c8c/zope_interface-8.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b361b7ce566bc024e55f74eb1e88afc14039d7bd8ea13eeff3b7a8400dc59683", size = 211571, upload-time = "2026-04-10T06:22:14.775Z" }, + { url = "https://files.pythonhosted.org/packages/cf/31/844979b472f30efd2a68480738c9a3be518786b0885137075616607e88c7/zope_interface-8.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5be73ca1304daa3046ee5835f7fa6b3badadf02102b570532dd57cd25dd72d6", size = 211748, upload-time = "2026-04-10T06:22:16.695Z" }, + { url = "https://files.pythonhosted.org/packages/6e/b6/71f5c9d8dde7334e1b67306fea5814c67eac92d871bb0dfc664c9f3355f1/zope_interface-8.3-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:961af756797e36c1e77f7d0dc8ac1322de0c071eaa1a641dbe3b790061968dd9", size = 264718, upload-time = "2026-04-10T06:22:19.473Z" }, + { url = "https://files.pythonhosted.org/packages/94/e3/5eab77fd6795ca37b9ed1aeea5290170018938549322003745bdcd939238/zope_interface-8.3-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6329f296b70f62043bf2df06eb91b4be040baee32ec4a3e0314f3893fa5c51c", size = 269795, upload-time = "2026-04-10T06:22:21.728Z" }, + { url = "https://files.pythonhosted.org/packages/a2/2f/4bc8807d65833f06335a49beb1786bafcf748cde7472ba14cdb4db463ba8/zope_interface-8.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f420f6c96307ff265981c510782f0ed97475107b78ca9fca0bb04fe36f363eb4", size = 269418, upload-time = "2026-04-10T06:22:23.802Z" }, + { url = "https://files.pythonhosted.org/packages/50/3d/1cfaf770bc6bc64edec3d4c5f17b5dbe600bf93cd2caac5ee0880eb9f9e0/zope_interface-8.3-cp312-cp312-win_amd64.whl", hash = "sha256:ffeae9102aa6ba5bd2f9a547016347bd87c9cf01aea564936c0d165fff0b1242", size = 214390, upload-time = "2026-04-10T06:22:25.735Z" }, + { url = "https://files.pythonhosted.org/packages/27/da/ff205c5463e52ad64cc40be667fdff2b01b9754a385c6b95bac01645fa4f/zope_interface-8.3-cp313-cp313-macosx_10_9_x86_64.whl", hash = "sha256:1aa0e1d72212cedc38b2156bbca08cf24625c057135a7947ef6b19bc732b2772", size = 211889, upload-time = "2026-04-10T06:22:27.612Z" }, + { url = "https://files.pythonhosted.org/packages/c7/21/0cc848e22769b1cf4c0cd636ec2e60ea05cfb958423435ea526d5a291fe8/zope_interface-8.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:54ab83218a8f6947ba4b6cb1a121f1e1abe2e418b838ccdac71639d0f97e734e", size = 211961, upload-time = "2026-04-10T06:22:29.575Z" }, + { url = "https://files.pythonhosted.org/packages/e3/54/815c9dbb90336c50694b4c7ef7ced06bc389e5597200c77457b557a0221c/zope_interface-8.3-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:34d6c10fa790005487c471e0e4ab537b0fa9a70e55a96994e51ffeef92205fa4", size = 264409, upload-time = "2026-04-10T06:22:31.426Z" }, + { url = "https://files.pythonhosted.org/packages/3a/69/2e5c30adde0e94552d934971fa6eba107449d3d11fa086cfcfeb8ea6354d/zope_interface-8.3-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:93108d5f8dee20177a637438bf4df4c6faf8a317c9d4a8b1d5e78123854e3317", size = 269592, upload-time = "2026-04-10T06:22:33.393Z" }, + { url = "https://files.pythonhosted.org/packages/23/8a/fbb1dceb5c5400b2b27934aa102d29fe4cb06732122e7f409efebeb6e097/zope_interface-8.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8f81d90f80b9fbf36602549e2f187861c9d7139837f8c9dd685ce3b933c6360f", size = 269548, upload-time = "2026-04-10T06:22:35.339Z" }, + { url = "https://files.pythonhosted.org/packages/a2/70/abd0bb9cc9b1a9a718f30c81f46a184a2e751dd80cf57db142ffa42730da/zope_interface-8.3-cp313-cp313-win_amd64.whl", hash = "sha256:96106a5f609bb355e1aec6ab0361213c8af0843ca1e1ba9c42eacfbd0910914e", size = 214391, upload-time = "2026-04-10T06:22:36.969Z" }, + { url = "https://files.pythonhosted.org/packages/8a/d9/95fe0d4d8da09042383c42f239e0106f1019ec86a27ed9f5000e754f6e7a/zope_interface-8.3-cp314-cp314-macosx_10_9_x86_64.whl", hash = "sha256:96f0001b49227d756770fc70ecde49f19332ae98ec98e1bbbf2fd7a87e9d4e45", size = 211979, upload-time = "2026-04-10T06:22:38.628Z" }, + { url = "https://files.pythonhosted.org/packages/f3/01/b6f694444ea1c911a4ea915f4ef066a95e9d1a58256a30c131ec88c3ae64/zope_interface-8.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3853bfb808084e1b4a3a769b00bd8b58a52b0c4a4fc5c23de26d283cd8beb627", size = 212038, upload-time = "2026-04-10T06:22:40.475Z" }, + { url = "https://files.pythonhosted.org/packages/f7/cf/237de1fba4f05686bc344eeb035236bd89890679c8211f129f05b5971ccf/zope_interface-8.3-cp314-cp314-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:33a13acba79ef693fb64ceb6193ece913d39586f184797f133c1bc549da86851", size = 266041, upload-time = "2026-04-10T06:22:42.093Z" }, + { url = "https://files.pythonhosted.org/packages/58/5f/df85b1ff5626d7f05231e69b7efd38bdc2c82ca363495e0bb112aaf655b3/zope_interface-8.3-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e9f7e4b46741a11a9e1fab8b68710f08dec700e9f1b877cdca02480fbebe4846", size = 269094, upload-time = "2026-04-10T06:22:43.832Z" }, + { url = "https://files.pythonhosted.org/packages/5f/10/7ad1ff9c514fe38b176fc1271967c453074eb386a4515bd3b957c485f3a8/zope_interface-8.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8ce49d43366e12aeccd14fcaebb3ef110f50f5795e0d4a95383ea057365cedf2", size = 269413, upload-time = "2026-04-10T06:22:45.573Z" }, + { url = "https://files.pythonhosted.org/packages/38/42/3b0b5edee7801e0dd5c42c2c9bb4ec8bec430a6628462eb1315db76a7954/zope_interface-8.3-cp314-cp314-win_amd64.whl", hash = "sha256:301db4049c79a15a3b29d89795e150daf0e9ae701404b112ad6585ea863f6ef5", size = 215170, upload-time = "2026-04-10T06:22:47.115Z" }, ]