From 5b4ed3d1caf6f912a9ef5ed7be847fa4a0accc81 Mon Sep 17 00:00:00 2001 From: Luis Gaspar Schroeder Date: Wed, 3 Sep 2025 09:42:09 +0200 Subject: [PATCH 1/4] Updated ReadMe --- README.md | 353 ++++++++++++++++++++++++++------------------------ docs/logo.png | Bin 0 -> 782786 bytes 2 files changed, 181 insertions(+), 172 deletions(-) create mode 100644 docs/logo.png diff --git a/README.md b/README.md index 4567b272..32f0696e 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,38 @@ -# Sparse Attention Hub +
+

+ + + + + Sparse Attention Hub + +

-A comprehensive framework for sparse attention mechanisms in deep learning models. This project provides implementations of various sparse attention algorithms, benchmarking tools, and seamless integration with popular model frameworks like HuggingFace Transformers. +
-## ๐Ÿš€ Features +**A framework for implementing and evaluating sparse attention mechanisms in transformer models** -- **Multiple Sparse Attention Algorithms**: Implementations of efficient attention mechanisms including Double Sparsity, Hash Attention, and various research-oriented masking strategies -- **Framework Integration**: Seamless integration with HuggingFace Transformers and other popular frameworks -- **Comprehensive Benchmarking**: Built-in support for LongBench, Loogle, InfBench, and custom benchmarks -- **Advanced Metrics**: Micro-metrics logging system for detailed performance analysis -- **Visualization Tools**: Generate plots and heatmaps for attention pattern analysis -- **Extensible Architecture**: Modular design for easy extension and customization +[![Python](https://img.shields.io/badge/Python-3.9+-3776AB?style=flat-square&logo=python&logoColor=white)](https://www.python.org/) +[![PyTorch](https://img.shields.io/badge/PyTorch-1.9+-EE4C2C?style=flat-square&logo=pytorch&logoColor=white)](https://pytorch.org/) +[![Transformers](https://img.shields.io/badge/๐Ÿค—%20Transformers-4.20+-yellow?style=flat-square)](https://huggingface.co/transformers/) +[![MIT License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](LICENSE) +[![pytest](https://img.shields.io/badge/pytest-Testing-0A9EDC?style=flat-square&logo=pytest&logoColor=white)](https://pytest.org/) +[![Code Style: Black](https://img.shields.io/badge/Code%20Style-Black-000000?style=flat-square)](https://github.com/psf/black) -## ๐Ÿ“ฆ Installation +
+ +Sparse Attention Hub provides efficient implementations of sparse attention algorithms for transformer models. It includes research-oriented attention mechanisms, production-ready implementations, comprehensive benchmarking tools, and seamless integration with HuggingFace Transformers. + +## Key Features + +- **Multiple Sparse Attention Algorithms**: Hash Attention, Double Sparsity, and configurable masking strategies +- **HuggingFace Integration**: Drop-in replacement for standard attention with minimal code changes +- **Comprehensive Benchmarking**: Built-in support for LongBench, Ruler, AIME, InfiniteBench, and custom datasets +- **Research Tools**: Flexible masker system for experimenting with novel attention patterns +- **Performance Monitoring**: Detailed metrics logging and visualization capabilities +- **Modular Architecture**: Easy to extend with custom attention mechanisms + +## Installation ### From Source @@ -23,256 +44,244 @@ pip install -e . ### Dependencies +The project requires Python 3.9+ and key dependencies include PyTorch, Transformers, and several benchmarking libraries. See `pyproject.toml` for the complete dependency list. + ```bash pip install -r requirements.txt ``` -## ๐Ÿ—๏ธ Architecture - -The framework is organized into several key modules: - -### Sparse Attention -- **Base Classes**: `SparseAttention`, `EfficientAttention`, `ResearchAttention` -- **Efficient Implementations**: `DoubleSparsity`, `HashAttention` -- **Research Maskers**: Various masking strategies for attention patterns -- **Generators**: Integration interfaces for different frameworks - -### Adapter System -- **ModelAdapterHF**: Unified adapter for HuggingFace integration -- **Request/RequestResponse**: Structured request/response handling -- **ModelAdapter**: Abstract base class for model adapters -- **ModelHubAdapterInterface**: Interface for model hosting libraries -- **SparseAttentionAdapterInterface**: Interface for sparse attention integration +## Quick Start -### Benchmarking -- **Benchmark**: Abstract benchmark interface -- **Datasets**: LongBench, Loogle, InfBench implementations -- **BenchmarkExecutor**: Execution and result management -- **ResultStorage**: Persistent storage for benchmark results - -### Metrics & Visualization -- **MicroMetricLogger**: Singleton logger for detailed metrics -- **MicroMetrics**: TopkRecall, LocalError, SampleVariance implementations -- **PlotGenerator**: Visualization tools with multiple granularity levels - -## ๐Ÿš€ Quick Start +### Basic Usage with HuggingFace Models ```python -from sparse_attention_hub.adapters import ModelAdapterHF, Request, RequestResponse -from sparse_attention_hub.sparse_attention.research_attention import ResearchAttentionConfig +from sparse_attention_hub.adapters import ModelAdapterHF, Request +from sparse_attention_hub.sparse_attention import ResearchAttentionConfig from sparse_attention_hub.sparse_attention.research_attention.maskers.fixed.implementations import ( LocalMaskerConfig, SinkMaskerConfig ) -from sparse_attention_hub.benchmark import BenchmarkExecutor -from sparse_attention_hub.plotting import PlotGenerator, Granularity - -# Create sparse attention configuration -local_config = LocalMaskerConfig(window_size=16) -sink_config = SinkMaskerConfig(sink_size=4) -sparse_attention_config = ResearchAttentionConfig( - masker_configs=[local_config, sink_config] -) + +# Configure sparse attention (StreamingLLM pattern) +sparse_config = ResearchAttentionConfig(masker_configs=[ + SinkMaskerConfig(sink_size=4), # Keep first 4 tokens + LocalMaskerConfig(window_size=64) # Keep last 64 tokens +]) # Create model adapter adapter = ModelAdapterHF( model_name="microsoft/DialoGPT-small", - sparse_attention_config=sparse_attention_config, + sparse_attention_config=sparse_config, device="auto" ) # Create request request = Request( - context="The capital of France is Paris. It is known for the Eiffel Tower.", - questions=["What is the capital of France?", "What is Paris known for?"] + context="Paris is the capital of France. It is famous for the Eiffel Tower and the Louvre Museum.", + questions=["What is the capital of France?", "What is Paris famous for?"] ) -# Process request with sparse attention +# Process with sparse attention with adapter.enable_sparse_mode(): response = adapter.process_request(request) - print(response.responses) # ['Paris', 'The Eiffel Tower'] + print(response.responses) -# Process request with dense attention (default) +# Process with dense attention (default) response = adapter.process_request(request) print(response.responses) - -# Run benchmarks and visualizations -benchmark_executor = BenchmarkExecutor() -plot_generator = PlotGenerator() -plot_path = plot_generator.generate_plot(Granularity.PER_HEAD) ``` -## ๐Ÿ“Š Benchmarking +### Available Sparse Attention Methods -The framework supports multiple benchmark datasets and integrates seamlessly with the new adapter system: +```python +# Hash Attention +from sparse_attention_hub.sparse_attention import HashAttentionConfig, EfficientAttentionConfig + +hash_config = EfficientAttentionConfig( + implementation_config=HashAttentionConfig( + num_hash_functions=4, + hash_budget=512 + ) +) -- **LongBench**: Long-context understanding tasks -- **Loogle**: Dependency tracking benchmarks -- **InfBench**: Infinite context benchmarks +# Double Sparsity +from sparse_attention_hub.sparse_attention import DoubleSparsityConfig -```python -from sparse_attention_hub.benchmark import BenchmarkExecutor -from sparse_attention_hub.benchmark.datasets import LongBench -from sparse_attention_hub.adapters import ModelAdapterHF +double_config = EfficientAttentionConfig( + implementation_config=DoubleSparsityConfig( + channel_config=ChannelConfig(channels_per_head=32), + sparsity_ratio=0.1 + ) +) -# Create adapter with sparse attention -adapter = ModelAdapterHF( - model_name="microsoft/DialoGPT-small", - sparse_attention_config=your_sparse_config +# Custom masking patterns +from sparse_attention_hub.sparse_attention.research_attention.maskers.fixed.implementations import ( + TopKMaskerConfig, OracleTopK ) -# Run benchmarks -executor = BenchmarkExecutor() -benchmark = LongBench() -results = executor.evaluate(benchmark, adapter) +custom_config = ResearchAttentionConfig(masker_configs=[ + TopKMaskerConfig(k=128), + SinkMaskerConfig(sink_size=4) +]) ``` -## ๐Ÿ“ˆ Metrics and Logging +## Benchmarking -Track detailed performance metrics: +### Running Benchmarks ```python -from sparse_attention_hub.metrics import MicroMetricLogger -from sparse_attention_hub.metrics.implementations import TopkRecall +from benchmark import BenchmarkExecutor, BenchmarkConfig +from benchmark.executor_config import AdapterConfig -logger = MicroMetricLogger() -metric = TopkRecall(k=10) -logger.register_metric(metric) -logger.enable_metric_logging(metric) +# Configure benchmark +benchmark_config = BenchmarkConfig( + benchmark_name="longbench", + subsets=["narrativeqa", "qasper"] +) -# Log metrics during model execution -logger.log("layer_1", metric, computed_value) +adapter_config = AdapterConfig( + model_name="microsoft/DialoGPT-small", + sparse_attention_config=sparse_config +) + +# Run evaluation +executor = BenchmarkExecutor( + result_dir="./results", + gpus=[0, 1], + max_concurrent_runs=2 +) + +results = executor.run_benchmarks( + benchmark_configs=[benchmark_config], + adapter_configs=[adapter_config] +) ``` -## ๐ŸŽจ Visualization +### Supported Benchmarks -Generate attention pattern visualizations: +- **LongBench**: Long-context understanding tasks (22 standard + 13 extended datasets) +- **Ruler**: Synthetic tasks for testing context length capabilities +- **AIME 2024/2025**: Mathematical reasoning benchmarks +- **InfiniteBench**: Infinite context evaluation tasks +- **Loogle**: Dependency tracking and retrieval tasks +- **ZeroScrolls**: Long document understanding +- **Custom benchmarks**: Easy to add new evaluation datasets -```python -from sparse_attention_hub.plotting import PlotGenerator, Granularity +## Architecture + +### Core Components -generator = PlotGenerator() +- **`sparse_attention/`**: Core sparse attention implementations + - `base.py`: Abstract interfaces for all attention mechanisms + - `efficient_attention/`: Production-ready algorithms (Hash Attention, Double Sparsity) + - `research_attention/`: Experimental masking strategies for research + - `utils/`: Common utilities and mask operations -# Generate different types of plots -token_plot = generator.generate_plot(Granularity.PER_TOKEN, data) -head_plot = generator.generate_plot(Granularity.PER_HEAD, data) -layer_plot = generator.generate_plot(Granularity.PER_LAYER, data) +- **`adapters/`**: Integration layer for different frameworks + - `huggingface.py`: HuggingFace Transformers integration + - `model_servers/`: Centralized model and tokenizer management + - `base.py`: Abstract adapter interfaces + +- **`benchmark/`**: Comprehensive benchmarking system + - Individual benchmark implementations (LongBench, Ruler, etc.) + - `executor.py`: Parallel execution with GPU management + - `base.py`: Abstract benchmark interface + +- **`metric_logging/`**: Performance monitoring and analysis +- **`plotting/`**: Visualization tools for attention patterns and results + +## Advanced Usage + +### Custom Maskers + +```python +from sparse_attention_hub.sparse_attention.research_attention.maskers.base import ResearchMasker +from sparse_attention_hub.sparse_attention.utils import Mask + +class CustomMasker(ResearchMasker): + def add_mask(self, keys, queries, values, previous_mask, **kwargs): + # Implement custom masking logic + custom_mask = self.create_custom_mask(queries.shape) + return previous_mask.combine_with(custom_mask) ``` -## ๐Ÿงช Testing +### Metrics and Monitoring -Run the test suite: +```python +from sparse_attention_hub.metric_logging import MicroMetricLogger + +logger = MicroMetricLogger() +# Metrics are automatically logged when using ResearchAttention +# Access logged data for analysis +metrics_data = logger.get_logged_metrics() +``` + +## Testing ```bash # Run all tests python scripts/run_tests.py --type all -# Run only unit tests +# Run specific test categories python scripts/run_tests.py --type unit - -# Run specific test -python scripts/run_tests.py --type specific --test-path tests/unit/test_metrics.py - -# Discover available tests -python scripts/run_tests.py --discover +python scripts/run_tests.py --type integration # Run tests with coverage make test-coverage ``` -## ๐Ÿ”ง Development Tools - -### Code Formatting and Linting +## Development -The project uses comprehensive linting and formatting tools: +### Code Quality Tools ```bash # Install development dependencies -pip install -r requirements-dev.txt +pip install -e ".[dev]" # Format code bash scripts/format.sh -# Run all linting checks +# Run linting bash scripts/lint.sh -# Run specific linters -bash scripts/lint.sh --flake8 -bash scripts/lint.sh --mypy -bash scripts/lint.sh --pylint -bash scripts/lint.sh --bandit - -# Using Make commands -make format # Format code -make lint # Run all linting -make dev-check # Quick format + lint check -``` - -### Pre-commit Hooks - -Set up pre-commit hooks for automatic code quality checks: - -```bash -# Install pre-commit hooks +# Set up pre-commit hooks pre-commit install - -# Run pre-commit on all files -pre-commit run --all-files - -# Update pre-commit hooks -pre-commit autoupdate ``` -### Development Workflow - -```bash -# Complete development setup -make dev-setup - -# Run all development checks -make dev-check - -# Simulate CI pipeline -make ci -``` - -## ๐Ÿ“ Project Structure +### Project Structure ``` sparse-attention-hub/ โ”œโ”€โ”€ sparse_attention_hub/ # Main package -โ”‚ โ”œโ”€โ”€ sparse_attention/ # Sparse attention implementations -โ”‚ โ”œโ”€โ”€ adapters/ # Model adapter system -โ”‚ โ”œโ”€โ”€ benchmark/ # Benchmarking tools -โ”‚ โ”œโ”€โ”€ metrics/ # Metrics and logging -โ”‚ โ”œโ”€โ”€ plotting/ # Visualization tools -โ”‚ โ””โ”€โ”€ testing/ # Testing utilities -โ”œโ”€โ”€ tests/ # Test suite -โ”‚ โ”œโ”€โ”€ unit/ # Unit tests -โ”‚ โ””โ”€โ”€ integration/ # Integration tests -โ”œโ”€โ”€ scripts/ # Utility scripts -โ”œโ”€โ”€ tutorials/ # Tutorial notebooks and examples +โ”‚ โ”œโ”€โ”€ sparse_attention/ # Sparse attention implementations +โ”‚ โ”œโ”€โ”€ adapters/ # Model integration adapters +โ”‚ โ”œโ”€โ”€ metric_logging/ # Performance monitoring +โ”‚ โ””โ”€โ”€ plotting/ # Visualization tools +โ”œโ”€โ”€ benchmark/ # Benchmarking framework +โ”‚ โ”œโ”€โ”€ longbench/ # LongBench implementation +โ”‚ โ”œโ”€โ”€ ruler/ # Ruler benchmark +โ”‚ โ”œโ”€โ”€ AIME2024/, AIME2025/ # Mathematical reasoning +โ”‚ โ””โ”€โ”€ scripts/ # Benchmark execution scripts +โ”œโ”€โ”€ tests/ # Test suite +โ”‚ โ”œโ”€โ”€ unit/ # Unit tests +โ”‚ โ””โ”€โ”€ integration/ # Integration tests +โ”œโ”€โ”€ tutorials/ # Examples and tutorials โ””โ”€โ”€ docs/ # Documentation ``` -## ๐Ÿค Contributing - -We welcome contributions! Please see our contributing guidelines for details on: +## Contributing -- Code style and formatting -- Testing requirements -- Documentation standards -- Pull request process +We welcome contributions to improve sparse attention implementations, add new benchmarks, or enhance the framework. Please ensure all code follows the project's formatting standards and includes appropriate tests. -## ๐Ÿ“„ License +## License -This project is licensed under the MIT License - see the LICENSE file for details. +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. -## ๐Ÿ”— Links +## Links - **Repository**: https://github.com/xAlg-ai/sparse-attention-hub - **Documentation**: https://sparse-attention-hub.readthedocs.io - **Issues**: https://github.com/xAlg-ai/sparse-attention-hub/issues -## ๐Ÿ™ Acknowledgments +## Acknowledgments -This project implements and extends various sparse attention mechanisms from the research community. We acknowledge the original authors of these algorithms and the open-source community for their contributions. \ No newline at end of file +This project implements sparse attention mechanisms from various research papers. We acknowledge the original authors and the open-source community for their contributions to advancing efficient attention algorithms. \ No newline at end of file diff --git a/docs/logo.png b/docs/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f4be273dde71abba3d6e99423e901ef709f46bcf GIT binary patch literal 782786 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≫WlvdLzk8I4I3scS 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

!dv+io(Za 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[}BM@&b<|Oi0Rjlow1dQ^1UESZ73fNe{ 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%0DIWPn1;a_i#_$LRnl03Tj}y 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 i|M%~I^A7mW-I_^oIM7YAU_HHu`6y&2 literal 0 HcmV?d00001 From 5ad64528790597f04aeda6bb0f0dd061b2124433 Mon Sep 17 00:00:00 2001 From: Luis Gaspar Schroeder Date: Wed, 3 Sep 2025 09:53:32 +0200 Subject: [PATCH 2/4] Added Poetry --- README.md | 33 +- poetry.lock | 5792 ++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 153 +- requirements-dev.txt | 38 - requirements.txt | 20 - scripts/format.sh | 18 +- scripts/lint.sh | 2 +- 7 files changed, 5901 insertions(+), 155 deletions(-) create mode 100644 poetry.lock delete mode 100644 requirements-dev.txt delete mode 100644 requirements.txt diff --git a/README.md b/README.md index 32f0696e..585172c6 100644 --- a/README.md +++ b/README.md @@ -34,22 +34,40 @@ Sparse Attention Hub provides efficient implementations of sparse attention algo ## Installation -### From Source +### Using Poetry (Recommended) ```bash +# Install Poetry if you haven't already +curl -sSL https://install.python-poetry.org | python3 - + +# Clone and install the project git clone https://github.com/xAlg-ai/sparse-attention-hub.git cd sparse-attention-hub -pip install -e . +poetry install ``` -### Dependencies +### Development Installation + +```bash +# Install with development dependencies +poetry install --with dev + +# Install with all optional dependencies +poetry install --with dev,docs,benchmarks +``` -The project requires Python 3.9+ and key dependencies include PyTorch, Transformers, and several benchmarking libraries. See `pyproject.toml` for the complete dependency list. +### From Source (pip) ```bash -pip install -r requirements.txt +git clone https://github.com/xAlg-ai/sparse-attention-hub.git +cd sparse-attention-hub +pip install -e . ``` +### Requirements + +The project requires Python 3.9+ and key dependencies include PyTorch, Transformers, and several benchmarking libraries. All dependencies are managed through Poetry and defined in `pyproject.toml`. + ## Quick Start ### Basic Usage with HuggingFace Models @@ -235,7 +253,10 @@ make test-coverage ```bash # Install development dependencies -pip install -e ".[dev]" +poetry install --with dev + +# Activate Poetry shell +poetry shell # Format code bash scripts/format.sh diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..c5ecf7b3 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,5792 @@ +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +description = "Happy Eyeballs for asyncio" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, + {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, +] + +[[package]] +name = "aiohttp" +version = "3.12.15" +description = "Async http client/server framework (asyncio)" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "aiohttp-3.12.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b6fc902bff74d9b1879ad55f5404153e2b33a82e72a95c89cec5eb6cc9e92fbc"}, + {file = "aiohttp-3.12.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:098e92835b8119b54c693f2f88a1dec690e20798ca5f5fe5f0520245253ee0af"}, + {file = "aiohttp-3.12.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:40b3fee496a47c3b4a39a731954c06f0bd9bd3e8258c059a4beb76ac23f8e421"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ce13fcfb0bb2f259fb42106cdc63fa5515fb85b7e87177267d89a771a660b79"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3beb14f053222b391bf9cf92ae82e0171067cc9c8f52453a0f1ec7c37df12a77"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c39e87afe48aa3e814cac5f535bc6199180a53e38d3f51c5e2530f5aa4ec58c"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5f1b4ce5bc528a6ee38dbf5f39bbf11dd127048726323b72b8e85769319ffc4"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1004e67962efabbaf3f03b11b4c43b834081c9e3f9b32b16a7d97d4708a9abe6"}, + {file = "aiohttp-3.12.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8faa08fcc2e411f7ab91d1541d9d597d3a90e9004180edb2072238c085eac8c2"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fe086edf38b2222328cdf89af0dde2439ee173b8ad7cb659b4e4c6f385b2be3d"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:79b26fe467219add81d5e47b4a4ba0f2394e8b7c7c3198ed36609f9ba161aecb"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b761bac1192ef24e16706d761aefcb581438b34b13a2f069a6d343ec8fb693a5"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e153e8adacfe2af562861b72f8bc47f8a5c08e010ac94eebbe33dc21d677cd5b"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:fc49c4de44977aa8601a00edbf157e9a421f227aa7eb477d9e3df48343311065"}, + {file = "aiohttp-3.12.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2776c7ec89c54a47029940177e75c8c07c29c66f73464784971d6a81904ce9d1"}, + {file = "aiohttp-3.12.15-cp310-cp310-win32.whl", hash = "sha256:2c7d81a277fa78b2203ab626ced1487420e8c11a8e373707ab72d189fcdad20a"}, + {file = "aiohttp-3.12.15-cp310-cp310-win_amd64.whl", hash = "sha256:83603f881e11f0f710f8e2327817c82e79431ec976448839f3cd05d7afe8f830"}, + {file = "aiohttp-3.12.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d3ce17ce0220383a0f9ea07175eeaa6aa13ae5a41f30bc61d84df17f0e9b1117"}, + {file = "aiohttp-3.12.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:010cc9bbd06db80fe234d9003f67e97a10fe003bfbedb40da7d71c1008eda0fe"}, + {file = "aiohttp-3.12.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f9d7c55b41ed687b9d7165b17672340187f87a773c98236c987f08c858145a9"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc4fbc61bb3548d3b482f9ac7ddd0f18c67e4225aaa4e8552b9f1ac7e6bda9e5"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7fbc8a7c410bb3ad5d595bb7118147dfbb6449d862cc1125cf8867cb337e8728"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74dad41b3458dbb0511e760fb355bb0b6689e0630de8a22b1b62a98777136e16"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b6f0af863cf17e6222b1735a756d664159e58855da99cfe965134a3ff63b0b0"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b7fe4972d48a4da367043b8e023fb70a04d1490aa7d68800e465d1b97e493b"}, + {file = "aiohttp-3.12.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6443cca89553b7a5485331bc9bedb2342b08d073fa10b8c7d1c60579c4a7b9bd"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c5f40ec615e5264f44b4282ee27628cea221fcad52f27405b80abb346d9f3f8"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2abbb216a1d3a2fe86dbd2edce20cdc5e9ad0be6378455b05ec7f77361b3ab50"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:db71ce547012a5420a39c1b744d485cfb823564d01d5d20805977f5ea1345676"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ced339d7c9b5030abad5854aa5413a77565e5b6e6248ff927d3e174baf3badf7"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7c7dd29c7b5bda137464dc9bfc738d7ceea46ff70309859ffde8c022e9b08ba7"}, + {file = "aiohttp-3.12.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:421da6fd326460517873274875c6c5a18ff225b40da2616083c5a34a7570b685"}, + {file = "aiohttp-3.12.15-cp311-cp311-win32.whl", hash = "sha256:4420cf9d179ec8dfe4be10e7d0fe47d6d606485512ea2265b0d8c5113372771b"}, + {file = "aiohttp-3.12.15-cp311-cp311-win_amd64.whl", hash = "sha256:edd533a07da85baa4b423ee8839e3e91681c7bfa19b04260a469ee94b778bf6d"}, + {file = "aiohttp-3.12.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7"}, + {file = "aiohttp-3.12.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444"}, + {file = "aiohttp-3.12.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545"}, + {file = "aiohttp-3.12.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea"}, + {file = "aiohttp-3.12.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3"}, + {file = "aiohttp-3.12.15-cp312-cp312-win32.whl", hash = "sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1"}, + {file = "aiohttp-3.12.15-cp312-cp312-win_amd64.whl", hash = "sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34"}, + {file = "aiohttp-3.12.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f922ffd05034d439dde1c77a20461cf4a1b0831e6caa26151fe7aa8aaebc315"}, + {file = "aiohttp-3.12.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ee8a8ac39ce45f3e55663891d4b1d15598c157b4d494a4613e704c8b43112cd"}, + {file = "aiohttp-3.12.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3eae49032c29d356b94eee45a3f39fdf4b0814b397638c2f718e96cfadf4c4e4"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97752ff12cc12f46a9b20327104448042fce5c33a624f88c18f66f9368091c7"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:894261472691d6fe76ebb7fcf2e5870a2ac284c7406ddc95823c8598a1390f0d"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fa5d9eb82ce98959fc1031c28198b431b4d9396894f385cb63f1e2f3f20ca6b"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fa751efb11a541f57db59c1dd821bec09031e01452b2b6217319b3a1f34f3d"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5346b93e62ab51ee2a9d68e8f73c7cf96ffb73568a23e683f931e52450e4148d"}, + {file = "aiohttp-3.12.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:049ec0360f939cd164ecbfd2873eaa432613d5e77d6b04535e3d1fbae5a9e645"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b52dcf013b57464b6d1e51b627adfd69a8053e84b7103a7cd49c030f9ca44461"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b2af240143dd2765e0fb661fd0361a1b469cab235039ea57663cda087250ea9"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac77f709a2cde2cc71257ab2d8c74dd157c67a0558a0d2799d5d571b4c63d44d"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:47f6b962246f0a774fbd3b6b7be25d59b06fdb2f164cf2513097998fc6a29693"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:760fb7db442f284996e39cf9915a94492e1896baac44f06ae551974907922b64"}, + {file = "aiohttp-3.12.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad702e57dc385cae679c39d318def49aef754455f237499d5b99bea4ef582e51"}, + {file = "aiohttp-3.12.15-cp313-cp313-win32.whl", hash = "sha256:f813c3e9032331024de2eb2e32a88d86afb69291fbc37a3a3ae81cc9917fb3d0"}, + {file = "aiohttp-3.12.15-cp313-cp313-win_amd64.whl", hash = "sha256:1a649001580bdb37c6fdb1bebbd7e3bc688e8ec2b5c6f52edbb664662b17dc84"}, + {file = "aiohttp-3.12.15-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:691d203c2bdf4f4637792efbbcdcd157ae11e55eaeb5e9c360c1206fb03d4d98"}, + {file = "aiohttp-3.12.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e995e1abc4ed2a454c731385bf4082be06f875822adc4c6d9eaadf96e20d406"}, + {file = "aiohttp-3.12.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bd44d5936ab3193c617bfd6c9a7d8d1085a8dc8c3f44d5f1dcf554d17d04cf7d"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46749be6e89cd78d6068cdf7da51dbcfa4321147ab8e4116ee6678d9a056a0cf"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0c643f4d75adea39e92c0f01b3fb83d57abdec8c9279b3078b68a3a52b3933b6"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a23918fedc05806966a2438489dcffccbdf83e921a1170773b6178d04ade142"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:74bdd8c864b36c3673741023343565d95bfbd778ffe1eb4d412c135a28a8dc89"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a146708808c9b7a988a4af3821379e379e0f0e5e466ca31a73dbdd0325b0263"}, + {file = "aiohttp-3.12.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7011a70b56facde58d6d26da4fec3280cc8e2a78c714c96b7a01a87930a9530"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3bdd6e17e16e1dbd3db74d7f989e8af29c4d2e025f9828e6ef45fbdee158ec75"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:57d16590a351dfc914670bd72530fd78344b885a00b250e992faea565b7fdc05"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:bc9a0f6569ff990e0bbd75506c8d8fe7214c8f6579cca32f0546e54372a3bb54"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:536ad7234747a37e50e7b6794ea868833d5220b49c92806ae2d7e8a9d6b5de02"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f0adb4177fa748072546fb650d9bd7398caaf0e15b370ed3317280b13f4083b0"}, + {file = "aiohttp-3.12.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:14954a2988feae3987f1eb49c706bff39947605f4b6fa4027c1d75743723eb09"}, + {file = "aiohttp-3.12.15-cp39-cp39-win32.whl", hash = "sha256:b784d6ed757f27574dca1c336f968f4e81130b27595e458e69457e6878251f5d"}, + {file = "aiohttp-3.12.15-cp39-cp39-win_amd64.whl", hash = "sha256:86ceded4e78a992f835209e236617bffae649371c4a50d5e5a3987f237db84b8"}, + {file = "aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2"}, +] + +[package.dependencies] +aiohappyeyeballs = ">=2.5.0" +aiosignal = ">=1.4.0" +async-timeout = {version = ">=4.0,<6.0", markers = "python_version < \"3.11\""} +attrs = ">=17.3.0" +frozenlist = ">=1.1.1" +multidict = ">=4.5,<7.0" +propcache = ">=0.2.0" +yarl = ">=1.17.0,<2.0" + +[package.extras] +speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "brotlicffi ; platform_python_implementation != \"CPython\""] + +[[package]] +name = "aiosignal" +version = "1.4.0" +description = "aiosignal: a list of registered asynchronous callbacks" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e"}, + {file = "aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7"}, +] + +[package.dependencies] +frozenlist = ">=1.1.0" +typing-extensions = {version = ">=4.2", markers = "python_version < \"3.13\""} + +[[package]] +name = "alabaster" +version = "0.7.16" +description = "A light, configurable Sphinx theme" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +markers = "python_version < \"3.11\"" +files = [ + {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, + {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, +] + +[[package]] +name = "alabaster" +version = "1.0.0" +description = "A light, configurable Sphinx theme" +optional = false +python-versions = ">=3.10" +groups = ["docs"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b"}, + {file = "alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e"}, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +groups = ["benchmarks"] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "astroid" +version = "2.15.8" +description = "An abstract syntax tree for Python with inference support." +optional = false +python-versions = ">=3.7.2" +groups = ["dev"] +files = [ + {file = "astroid-2.15.8-py3-none-any.whl", hash = "sha256:1aa149fc5c6589e3d0ece885b4491acd80af4f087baafa3fb5203b113e68cd3c"}, + {file = "astroid-2.15.8.tar.gz", hash = "sha256:6c107453dffee9055899705de3c9ead36e74119cee151e5a9aaf7f0b0e020a6a"}, +] + +[package.dependencies] +lazy-object-proxy = ">=1.4.0" +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} +wrapt = [ + {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, + {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, +] + +[[package]] +name = "async-timeout" +version = "5.0.1" +description = "Timeout context manager for asyncio programs" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version < \"3.11\"" +files = [ + {file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"}, + {file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"}, +] + +[[package]] +name = "attrs" +version = "25.3.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, +] + +[package.extras] +benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] +tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""] + +[[package]] +name = "babel" +version = "2.17.0" +description = "Internationalization utilities" +optional = false +python-versions = ">=3.8" +groups = ["docs"] +files = [ + {file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"}, + {file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"}, +] + +[package.extras] +dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] + +[[package]] +name = "bandit" +version = "1.8.6" +description = "Security oriented static analyser for python code." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "bandit-1.8.6-py3-none-any.whl", hash = "sha256:3348e934d736fcdb68b6aa4030487097e23a501adf3e7827b63658df464dddd0"}, + {file = "bandit-1.8.6.tar.gz", hash = "sha256:dbfe9c25fc6961c2078593de55fd19f2559f9e45b99f1272341f5b95dea4e56b"}, +] + +[package.dependencies] +colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} +PyYAML = ">=5.3.1" +rich = "*" +stevedore = ">=1.20.0" + +[package.extras] +baseline = ["GitPython (>=3.1.30)"] +sarif = ["jschema-to-python (>=1.2.3)", "sarif-om (>=1.0.4)"] +test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)"] +toml = ["tomli (>=1.1.0) ; python_version < \"3.11\""] +yaml = ["PyYAML"] + +[[package]] +name = "bert-score" +version = "0.3.13" +description = "PyTorch implementation of BERT score" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "bert_score-0.3.13-py3-none-any.whl", hash = "sha256:bbbb4c7fcdaa46d7681aff49f37f96faa09ed74e1b150e659bdc6b58a66989b9"}, + {file = "bert_score-0.3.13.tar.gz", hash = "sha256:8ffe5838eac8cdd988b8b1a896af7f49071188c8c011a1ed160d71a9899a2ba4"}, +] + +[package.dependencies] +matplotlib = "*" +numpy = "*" +packaging = ">=20.9" +pandas = ">=1.0.1" +requests = "*" +torch = ">=1.0.0" +tqdm = ">=4.31.1" +transformers = ">=3.0.0" + +[[package]] +name = "black" +version = "22.10.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"}, + {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"}, + {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"}, + {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"}, + {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"}, + {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"}, + {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"}, + {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"}, + {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"}, + {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"}, + {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"}, + {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"}, + {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"}, + {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"}, + {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"}, + {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"}, + {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"}, + {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"}, + {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"}, + {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"}, + {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "certifi" +version = "2025.8.3" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.7" +groups = ["main", "benchmarks", "docs"] +files = [ + {file = "certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5"}, + {file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"}, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.3" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7" +groups = ["main", "benchmarks", "dev", "docs"] +files = [ + {file = "charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-win32.whl", hash = "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-win32.whl", hash = "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0f2be7e0cf7754b9a30eb01f4295cc3d4358a479843b31f328afd210e2c7598c"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c60e092517a73c632ec38e290eba714e9627abe9d301c8c8a12ec32c314a2a4b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:252098c8c7a873e17dd696ed98bbe91dbacd571da4b87df3736768efa7a792e4"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3653fad4fe3ed447a596ae8638b437f827234f01a8cd801842e43f3d0a6b281b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8999f965f922ae054125286faf9f11bc6932184b93011d138925a1773830bbe9"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d95bfb53c211b57198bb91c46dd5a2d8018b3af446583aab40074bf7988401cb"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:5b413b0b1bfd94dbf4023ad6945889f374cd24e3f62de58d6bb102c4d9ae534a"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:b5e3b2d152e74e100a9e9573837aba24aab611d39428ded46f4e4022ea7d1942"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a2d08ac246bb48479170408d6c19f6385fa743e7157d716e144cad849b2dd94b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-win32.whl", hash = "sha256:ec557499516fc90fd374bf2e32349a2887a876fbf162c160e3c01b6849eaf557"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:5d8d01eac18c423815ed4f4a2ec3b439d654e55ee4ad610e153cf02faf67ea40"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-win32.whl", hash = "sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca"}, + {file = "charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a"}, + {file = "charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14"}, +] + +[[package]] +name = "click" +version = "8.1.8" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +groups = ["main", "benchmarks", "dev"] +markers = "python_version < \"3.11\"" +files = [ + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "click" +version = "8.2.1" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.10" +groups = ["main", "benchmarks", "dev"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b"}, + {file = "click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "benchmarks", "dev", "docs"] +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "contourpy" +version = "1.3.0" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version < \"3.11\"" +files = [ + {file = "contourpy-1.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:880ea32e5c774634f9fcd46504bf9f080a41ad855f4fef54f5380f5133d343c7"}, + {file = "contourpy-1.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:76c905ef940a4474a6289c71d53122a4f77766eef23c03cd57016ce19d0f7b42"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92f8557cbb07415a4d6fa191f20fd9d2d9eb9c0b61d1b2f52a8926e43c6e9af7"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36f965570cff02b874773c49bfe85562b47030805d7d8360748f3eca570f4cab"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cacd81e2d4b6f89c9f8a5b69b86490152ff39afc58a95af002a398273e5ce589"}, + {file = "contourpy-1.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69375194457ad0fad3a839b9e29aa0b0ed53bb54db1bfb6c3ae43d111c31ce41"}, + {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a52040312b1a858b5e31ef28c2e865376a386c60c0e248370bbea2d3f3b760d"}, + {file = "contourpy-1.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3faeb2998e4fcb256542e8a926d08da08977f7f5e62cf733f3c211c2a5586223"}, + {file = "contourpy-1.3.0-cp310-cp310-win32.whl", hash = "sha256:36e0cff201bcb17a0a8ecc7f454fe078437fa6bda730e695a92f2d9932bd507f"}, + {file = "contourpy-1.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:87ddffef1dbe5e669b5c2440b643d3fdd8622a348fe1983fad7a0f0ccb1cd67b"}, + {file = "contourpy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fa4c02abe6c446ba70d96ece336e621efa4aecae43eaa9b030ae5fb92b309ad"}, + {file = "contourpy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:834e0cfe17ba12f79963861e0f908556b2cedd52e1f75e6578801febcc6a9f49"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbc4c3217eee163fa3984fd1567632b48d6dfd29216da3ded3d7b844a8014a66"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4865cd1d419e0c7a7bf6de1777b185eebdc51470800a9f42b9e9decf17762081"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:303c252947ab4b14c08afeb52375b26781ccd6a5ccd81abcdfc1fafd14cf93c1"}, + {file = "contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637f674226be46f6ba372fd29d9523dd977a291f66ab2a74fbeb5530bb3f445d"}, + {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:76a896b2f195b57db25d6b44e7e03f221d32fe318d03ede41f8b4d9ba1bff53c"}, + {file = "contourpy-1.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e1fd23e9d01591bab45546c089ae89d926917a66dceb3abcf01f6105d927e2cb"}, + {file = "contourpy-1.3.0-cp311-cp311-win32.whl", hash = "sha256:d402880b84df3bec6eab53cd0cf802cae6a2ef9537e70cf75e91618a3801c20c"}, + {file = "contourpy-1.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:6cb6cc968059db9c62cb35fbf70248f40994dfcd7aa10444bbf8b3faeb7c2d67"}, + {file = "contourpy-1.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:570ef7cf892f0afbe5b2ee410c507ce12e15a5fa91017a0009f79f7d93a1268f"}, + {file = "contourpy-1.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:da84c537cb8b97d153e9fb208c221c45605f73147bd4cadd23bdae915042aad6"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0be4d8425bfa755e0fd76ee1e019636ccc7c29f77a7c86b4328a9eb6a26d0639"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c0da700bf58f6e0b65312d0a5e695179a71d0163957fa381bb3c1f72972537c"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb8b141bb00fa977d9122636b16aa67d37fd40a3d8b52dd837e536d64b9a4d06"}, + {file = "contourpy-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3634b5385c6716c258d0419c46d05c8aa7dc8cb70326c9a4fb66b69ad2b52e09"}, + {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0dce35502151b6bd35027ac39ba6e5a44be13a68f55735c3612c568cac3805fd"}, + {file = "contourpy-1.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea348f053c645100612b333adc5983d87be69acdc6d77d3169c090d3b01dc35"}, + {file = "contourpy-1.3.0-cp312-cp312-win32.whl", hash = "sha256:90f73a5116ad1ba7174341ef3ea5c3150ddf20b024b98fb0c3b29034752c8aeb"}, + {file = "contourpy-1.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:b11b39aea6be6764f84360fce6c82211a9db32a7c7de8fa6dd5397cf1d079c3b"}, + {file = "contourpy-1.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3e1c7fa44aaae40a2247e2e8e0627f4bea3dd257014764aa644f319a5f8600e3"}, + {file = "contourpy-1.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:364174c2a76057feef647c802652f00953b575723062560498dc7930fc9b1cb7"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32b238b3b3b649e09ce9aaf51f0c261d38644bdfa35cbaf7b263457850957a84"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d51fca85f9f7ad0b65b4b9fe800406d0d77017d7270d31ec3fb1cc07358fdea0"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:732896af21716b29ab3e988d4ce14bc5133733b85956316fb0c56355f398099b"}, + {file = "contourpy-1.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d73f659398a0904e125280836ae6f88ba9b178b2fed6884f3b1f95b989d2c8da"}, + {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c6c7c2408b7048082932cf4e641fa3b8ca848259212f51c8c59c45aa7ac18f14"}, + {file = "contourpy-1.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f317576606de89da6b7e0861cf6061f6146ead3528acabff9236458a6ba467f8"}, + {file = "contourpy-1.3.0-cp313-cp313-win32.whl", hash = "sha256:31cd3a85dbdf1fc002280c65caa7e2b5f65e4a973fcdf70dd2fdcb9868069294"}, + {file = "contourpy-1.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:4553c421929ec95fb07b3aaca0fae668b2eb5a5203d1217ca7c34c063c53d087"}, + {file = "contourpy-1.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:345af746d7766821d05d72cb8f3845dfd08dd137101a2cb9b24de277d716def8"}, + {file = "contourpy-1.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3bb3808858a9dc68f6f03d319acd5f1b8a337e6cdda197f02f4b8ff67ad2057b"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:420d39daa61aab1221567b42eecb01112908b2cab7f1b4106a52caaec8d36973"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d63ee447261e963af02642ffcb864e5a2ee4cbfd78080657a9880b8b1868e18"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:167d6c890815e1dac9536dca00828b445d5d0df4d6a8c6adb4a7ec3166812fa8"}, + {file = "contourpy-1.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:710a26b3dc80c0e4febf04555de66f5fd17e9cf7170a7b08000601a10570bda6"}, + {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:75ee7cb1a14c617f34a51d11fa7524173e56551646828353c4af859c56b766e2"}, + {file = "contourpy-1.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:33c92cdae89ec5135d036e7218e69b0bb2851206077251f04a6c4e0e21f03927"}, + {file = "contourpy-1.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a11077e395f67ffc2c44ec2418cfebed032cd6da3022a94fc227b6faf8e2acb8"}, + {file = "contourpy-1.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e8134301d7e204c88ed7ab50028ba06c683000040ede1d617298611f9dc6240c"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e12968fdfd5bb45ffdf6192a590bd8ddd3ba9e58360b29683c6bb71a7b41edca"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fd2a0fc506eccaaa7595b7e1418951f213cf8255be2600f1ea1b61e46a60c55f"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4cfb5c62ce023dfc410d6059c936dcf96442ba40814aefbfa575425a3a7f19dc"}, + {file = "contourpy-1.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68a32389b06b82c2fdd68276148d7b9275b5f5cf13e5417e4252f6d1a34f72a2"}, + {file = "contourpy-1.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:94e848a6b83da10898cbf1311a815f770acc9b6a3f2d646f330d57eb4e87592e"}, + {file = "contourpy-1.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d78ab28a03c854a873787a0a42254a0ccb3cb133c672f645c9f9c8f3ae9d0800"}, + {file = "contourpy-1.3.0-cp39-cp39-win32.whl", hash = "sha256:81cb5ed4952aae6014bc9d0421dec7c5835c9c8c31cdf51910b708f548cf58e5"}, + {file = "contourpy-1.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:14e262f67bd7e6eb6880bc564dcda30b15e351a594657e55b7eec94b6ef72843"}, + {file = "contourpy-1.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fe41b41505a5a33aeaed2a613dccaeaa74e0e3ead6dd6fd3a118fb471644fd6c"}, + {file = "contourpy-1.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eca7e17a65f72a5133bdbec9ecf22401c62bcf4821361ef7811faee695799779"}, + {file = "contourpy-1.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1ec4dc6bf570f5b22ed0d7efba0dfa9c5b9e0431aeea7581aa217542d9e809a4"}, + {file = "contourpy-1.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:00ccd0dbaad6d804ab259820fa7cb0b8036bda0686ef844d24125d8287178ce0"}, + {file = "contourpy-1.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca947601224119117f7c19c9cdf6b3ab54c5726ef1d906aa4a69dfb6dd58102"}, + {file = "contourpy-1.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6ec93afeb848a0845a18989da3beca3eec2c0f852322efe21af1931147d12cb"}, + {file = "contourpy-1.3.0.tar.gz", hash = "sha256:7ffa0db17717a8ffb127efd0c95a4362d996b892c2904db72428d5b52e1938a4"}, +] + +[package.dependencies] +numpy = ">=1.23" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.11.1)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"] + +[[package]] +name = "contourpy" +version = "1.3.3" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = false +python-versions = ">=3.11" +groups = ["main"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1"}, + {file = "contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381"}, + {file = "contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7"}, + {file = "contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1"}, + {file = "contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a"}, + {file = "contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db"}, + {file = "contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620"}, + {file = "contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f"}, + {file = "contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff"}, + {file = "contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42"}, + {file = "contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470"}, + {file = "contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb"}, + {file = "contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6"}, + {file = "contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7"}, + {file = "contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8"}, + {file = "contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea"}, + {file = "contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1"}, + {file = "contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7"}, + {file = "contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411"}, + {file = "contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69"}, + {file = "contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b"}, + {file = "contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc"}, + {file = "contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5"}, + {file = "contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1"}, + {file = "contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286"}, + {file = "contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5"}, + {file = "contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67"}, + {file = "contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9"}, + {file = "contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659"}, + {file = "contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7"}, + {file = "contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d"}, + {file = "contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263"}, + {file = "contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9"}, + {file = "contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d"}, + {file = "contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216"}, + {file = "contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae"}, + {file = "contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20"}, + {file = "contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99"}, + {file = "contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b"}, + {file = "contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a"}, + {file = "contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e"}, + {file = "contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3"}, + {file = "contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8"}, + {file = "contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301"}, + {file = "contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a"}, + {file = "contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77"}, + {file = "contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5"}, + {file = "contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4"}, + {file = "contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36"}, + {file = "contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3"}, + {file = "contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b"}, + {file = "contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36"}, + {file = "contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d"}, + {file = "contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd"}, + {file = "contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339"}, + {file = "contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772"}, + {file = "contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77"}, + {file = "contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13"}, + {file = "contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe"}, + {file = "contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f"}, + {file = "contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0"}, + {file = "contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4"}, + {file = "contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f"}, + {file = "contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae"}, + {file = "contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc"}, + {file = "contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b"}, + {file = "contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497"}, + {file = "contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8"}, + {file = "contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e"}, + {file = "contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989"}, + {file = "contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77"}, + {file = "contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880"}, +] + +[package.dependencies] +numpy = ">=1.25" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] +mypy = ["bokeh", "contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.17.0)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"] + +[[package]] +name = "coverage" +version = "7.10.6" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "coverage-7.10.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:70e7bfbd57126b5554aa482691145f798d7df77489a177a6bef80de78860a356"}, + {file = "coverage-7.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e41be6f0f19da64af13403e52f2dec38bbc2937af54df8ecef10850ff8d35301"}, + {file = "coverage-7.10.6-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c61fc91ab80b23f5fddbee342d19662f3d3328173229caded831aa0bd7595460"}, + {file = "coverage-7.10.6-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10356fdd33a7cc06e8051413140bbdc6f972137508a3572e3f59f805cd2832fd"}, + {file = "coverage-7.10.6-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:80b1695cf7c5ebe7b44bf2521221b9bb8cdf69b1f24231149a7e3eb1ae5fa2fb"}, + {file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2e4c33e6378b9d52d3454bd08847a8651f4ed23ddbb4a0520227bd346382bbc6"}, + {file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c8a3ec16e34ef980a46f60dc6ad86ec60f763c3f2fa0db6d261e6e754f72e945"}, + {file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7d79dabc0a56f5af990cc6da9ad1e40766e82773c075f09cc571e2076fef882e"}, + {file = "coverage-7.10.6-cp310-cp310-win32.whl", hash = "sha256:86b9b59f2b16e981906e9d6383eb6446d5b46c278460ae2c36487667717eccf1"}, + {file = "coverage-7.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:e132b9152749bd33534e5bd8565c7576f135f157b4029b975e15ee184325f528"}, + {file = "coverage-7.10.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c706db3cabb7ceef779de68270150665e710b46d56372455cd741184f3868d8f"}, + {file = "coverage-7.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e0c38dc289e0508ef68ec95834cb5d2e96fdbe792eaccaa1bccac3966bbadcc"}, + {file = "coverage-7.10.6-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:752a3005a1ded28f2f3a6e8787e24f28d6abe176ca64677bcd8d53d6fe2ec08a"}, + {file = "coverage-7.10.6-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:689920ecfd60f992cafca4f5477d55720466ad2c7fa29bb56ac8d44a1ac2b47a"}, + {file = "coverage-7.10.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec98435796d2624d6905820a42f82149ee9fc4f2d45c2c5bc5a44481cc50db62"}, + {file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b37201ce4a458c7a758ecc4efa92fa8ed783c66e0fa3c42ae19fc454a0792153"}, + {file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2904271c80898663c810a6b067920a61dd8d38341244a3605bd31ab55250dad5"}, + {file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5aea98383463d6e1fa4e95416d8de66f2d0cb588774ee20ae1b28df826bcb619"}, + {file = "coverage-7.10.6-cp311-cp311-win32.whl", hash = "sha256:e3fb1fa01d3598002777dd259c0c2e6d9d5e10e7222976fc8e03992f972a2cba"}, + {file = "coverage-7.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:f35ed9d945bece26553d5b4c8630453169672bea0050a564456eb88bdffd927e"}, + {file = "coverage-7.10.6-cp311-cp311-win_arm64.whl", hash = "sha256:99e1a305c7765631d74b98bf7dbf54eeea931f975e80f115437d23848ee8c27c"}, + {file = "coverage-7.10.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5b2dd6059938063a2c9fee1af729d4f2af28fd1a545e9b7652861f0d752ebcea"}, + {file = "coverage-7.10.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:388d80e56191bf846c485c14ae2bc8898aa3124d9d35903fef7d907780477634"}, + {file = "coverage-7.10.6-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:90cb5b1a4670662719591aa92d0095bb41714970c0b065b02a2610172dbf0af6"}, + {file = "coverage-7.10.6-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:961834e2f2b863a0e14260a9a273aff07ff7818ab6e66d2addf5628590c628f9"}, + {file = "coverage-7.10.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf9a19f5012dab774628491659646335b1928cfc931bf8d97b0d5918dd58033c"}, + {file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:99c4283e2a0e147b9c9cc6bc9c96124de9419d6044837e9799763a0e29a7321a"}, + {file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:282b1b20f45df57cc508c1e033403f02283adfb67d4c9c35a90281d81e5c52c5"}, + {file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cdbe264f11afd69841bd8c0d83ca10b5b32853263ee62e6ac6a0ab63895f972"}, + {file = "coverage-7.10.6-cp312-cp312-win32.whl", hash = "sha256:a517feaf3a0a3eca1ee985d8373135cfdedfbba3882a5eab4362bda7c7cf518d"}, + {file = "coverage-7.10.6-cp312-cp312-win_amd64.whl", hash = "sha256:856986eadf41f52b214176d894a7de05331117f6035a28ac0016c0f63d887629"}, + {file = "coverage-7.10.6-cp312-cp312-win_arm64.whl", hash = "sha256:acf36b8268785aad739443fa2780c16260ee3fa09d12b3a70f772ef100939d80"}, + {file = "coverage-7.10.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ffea0575345e9ee0144dfe5701aa17f3ba546f8c3bb48db62ae101afb740e7d6"}, + {file = "coverage-7.10.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:95d91d7317cde40a1c249d6b7382750b7e6d86fad9d8eaf4fa3f8f44cf171e80"}, + {file = "coverage-7.10.6-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e23dd5408fe71a356b41baa82892772a4cefcf758f2ca3383d2aa39e1b7a003"}, + {file = "coverage-7.10.6-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f3f56e4cb573755e96a16501a98bf211f100463d70275759e73f3cbc00d4f27"}, + {file = "coverage-7.10.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db4a1d897bbbe7339946ffa2fe60c10cc81c43fab8b062d3fcb84188688174a4"}, + {file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d8fd7879082953c156d5b13c74aa6cca37f6a6f4747b39538504c3f9c63d043d"}, + {file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:28395ca3f71cd103b8c116333fa9db867f3a3e1ad6a084aa3725ae002b6583bc"}, + {file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:61c950fc33d29c91b9e18540e1aed7d9f6787cc870a3e4032493bbbe641d12fc"}, + {file = "coverage-7.10.6-cp313-cp313-win32.whl", hash = "sha256:160c00a5e6b6bdf4e5984b0ef21fc860bc94416c41b7df4d63f536d17c38902e"}, + {file = "coverage-7.10.6-cp313-cp313-win_amd64.whl", hash = "sha256:628055297f3e2aa181464c3808402887643405573eb3d9de060d81531fa79d32"}, + {file = "coverage-7.10.6-cp313-cp313-win_arm64.whl", hash = "sha256:df4ec1f8540b0bcbe26ca7dd0f541847cc8a108b35596f9f91f59f0c060bfdd2"}, + {file = "coverage-7.10.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c9a8b7a34a4de3ed987f636f71881cd3b8339f61118b1aa311fbda12741bff0b"}, + {file = "coverage-7.10.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dd5af36092430c2b075cee966719898f2ae87b636cefb85a653f1d0ba5d5393"}, + {file = "coverage-7.10.6-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0353b0f0850d49ada66fdd7d0c7cdb0f86b900bb9e367024fd14a60cecc1e27"}, + {file = "coverage-7.10.6-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d6b9ae13d5d3e8aeca9ca94198aa7b3ebbc5acfada557d724f2a1f03d2c0b0df"}, + {file = "coverage-7.10.6-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:675824a363cc05781b1527b39dc2587b8984965834a748177ee3c37b64ffeafb"}, + {file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:692d70ea725f471a547c305f0d0fc6a73480c62fb0da726370c088ab21aed282"}, + {file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:851430a9a361c7a8484a36126d1d0ff8d529d97385eacc8dfdc9bfc8c2d2cbe4"}, + {file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d9369a23186d189b2fc95cc08b8160ba242057e887d766864f7adf3c46b2df21"}, + {file = "coverage-7.10.6-cp313-cp313t-win32.whl", hash = "sha256:92be86fcb125e9bda0da7806afd29a3fd33fdf58fba5d60318399adf40bf37d0"}, + {file = "coverage-7.10.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6b3039e2ca459a70c79523d39347d83b73f2f06af5624905eba7ec34d64d80b5"}, + {file = "coverage-7.10.6-cp313-cp313t-win_arm64.whl", hash = "sha256:3fb99d0786fe17b228eab663d16bee2288e8724d26a199c29325aac4b0319b9b"}, + {file = "coverage-7.10.6-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6008a021907be8c4c02f37cdc3ffb258493bdebfeaf9a839f9e71dfdc47b018e"}, + {file = "coverage-7.10.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5e75e37f23eb144e78940b40395b42f2321951206a4f50e23cfd6e8a198d3ceb"}, + {file = "coverage-7.10.6-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0f7cb359a448e043c576f0da00aa8bfd796a01b06aa610ca453d4dde09cc1034"}, + {file = "coverage-7.10.6-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c68018e4fc4e14b5668f1353b41ccf4bc83ba355f0e1b3836861c6f042d89ac1"}, + {file = "coverage-7.10.6-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cd4b2b0707fc55afa160cd5fc33b27ccbf75ca11d81f4ec9863d5793fc6df56a"}, + {file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4cec13817a651f8804a86e4f79d815b3b28472c910e099e4d5a0e8a3b6a1d4cb"}, + {file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f2a6a8e06bbda06f78739f40bfb56c45d14eb8249d0f0ea6d4b3d48e1f7c695d"}, + {file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:081b98395ced0d9bcf60ada7661a0b75f36b78b9d7e39ea0790bb4ed8da14747"}, + {file = "coverage-7.10.6-cp314-cp314-win32.whl", hash = "sha256:6937347c5d7d069ee776b2bf4e1212f912a9f1f141a429c475e6089462fcecc5"}, + {file = "coverage-7.10.6-cp314-cp314-win_amd64.whl", hash = "sha256:adec1d980fa07e60b6ef865f9e5410ba760e4e1d26f60f7e5772c73b9a5b0713"}, + {file = "coverage-7.10.6-cp314-cp314-win_arm64.whl", hash = "sha256:a80f7aef9535442bdcf562e5a0d5a5538ce8abe6bb209cfbf170c462ac2c2a32"}, + {file = "coverage-7.10.6-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:0de434f4fbbe5af4fa7989521c655c8c779afb61c53ab561b64dcee6149e4c65"}, + {file = "coverage-7.10.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6e31b8155150c57e5ac43ccd289d079eb3f825187d7c66e755a055d2c85794c6"}, + {file = "coverage-7.10.6-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:98cede73eb83c31e2118ae8d379c12e3e42736903a8afcca92a7218e1f2903b0"}, + {file = "coverage-7.10.6-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f863c08f4ff6b64fa8045b1e3da480f5374779ef187f07b82e0538c68cb4ff8e"}, + {file = "coverage-7.10.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b38261034fda87be356f2c3f42221fdb4171c3ce7658066ae449241485390d5"}, + {file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e93b1476b79eae849dc3872faeb0bf7948fd9ea34869590bc16a2a00b9c82a7"}, + {file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ff8a991f70f4c0cf53088abf1e3886edcc87d53004c7bb94e78650b4d3dac3b5"}, + {file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ac765b026c9f33044419cbba1da913cfb82cca1b60598ac1c7a5ed6aac4621a0"}, + {file = "coverage-7.10.6-cp314-cp314t-win32.whl", hash = "sha256:441c357d55f4936875636ef2cfb3bee36e466dcf50df9afbd398ce79dba1ebb7"}, + {file = "coverage-7.10.6-cp314-cp314t-win_amd64.whl", hash = "sha256:073711de3181b2e204e4870ac83a7c4853115b42e9cd4d145f2231e12d670930"}, + {file = "coverage-7.10.6-cp314-cp314t-win_arm64.whl", hash = "sha256:137921f2bac5559334ba66122b753db6dc5d1cf01eb7b64eb412bb0d064ef35b"}, + {file = "coverage-7.10.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90558c35af64971d65fbd935c32010f9a2f52776103a259f1dee865fe8259352"}, + {file = "coverage-7.10.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8953746d371e5695405806c46d705a3cd170b9cc2b9f93953ad838f6c1e58612"}, + {file = "coverage-7.10.6-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c83f6afb480eae0313114297d29d7c295670a41c11b274e6bca0c64540c1ce7b"}, + {file = "coverage-7.10.6-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7eb68d356ba0cc158ca535ce1381dbf2037fa8cb5b1ae5ddfc302e7317d04144"}, + {file = "coverage-7.10.6-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b15a87265e96307482746d86995f4bff282f14b027db75469c446da6127433b"}, + {file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fc53ba868875bfbb66ee447d64d6413c2db91fddcfca57025a0e7ab5b07d5862"}, + {file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:efeda443000aa23f276f4df973cb82beca682fd800bb119d19e80504ffe53ec2"}, + {file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9702b59d582ff1e184945d8b501ffdd08d2cee38d93a2206aa5f1365ce0b8d78"}, + {file = "coverage-7.10.6-cp39-cp39-win32.whl", hash = "sha256:2195f8e16ba1a44651ca684db2ea2b2d4b5345da12f07d9c22a395202a05b23c"}, + {file = "coverage-7.10.6-cp39-cp39-win_amd64.whl", hash = "sha256:f32ff80e7ef6a5b5b606ea69a36e97b219cd9dc799bcf2963018a4d8f788cfbf"}, + {file = "coverage-7.10.6-py3-none-any.whl", hash = "sha256:92c4ecf6bf11b2e85fd4d8204814dc26e6a19f0c9d938c207c5cb0eadfcabbe3"}, + {file = "coverage-7.10.6.tar.gz", hash = "sha256:f644a3ae5933a552a29dbb9aa2f90c677a875f80ebea028e5a52a4f429044b90"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] + +[[package]] +name = "cycler" +version = "0.12.1" +description = "Composable style cycles" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, +] + +[package.extras] +docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] +tests = ["pytest", "pytest-cov", "pytest-xdist"] + +[[package]] +name = "datasets" +version = "4.0.0" +description = "HuggingFace community-driven open-source library of datasets" +optional = false +python-versions = ">=3.9.0" +groups = ["main"] +files = [ + {file = "datasets-4.0.0-py3-none-any.whl", hash = "sha256:7ef95e62025fd122882dbce6cb904c8cd3fbc829de6669a5eb939c77d50e203d"}, + {file = "datasets-4.0.0.tar.gz", hash = "sha256:9657e7140a9050db13443ba21cb5de185af8af944479b00e7ff1e00a61c8dbf1"}, +] + +[package.dependencies] +dill = ">=0.3.0,<0.3.9" +filelock = "*" +fsspec = {version = ">=2023.1.0,<=2025.3.0", extras = ["http"]} +huggingface-hub = ">=0.24.0" +multiprocess = "<0.70.17" +numpy = ">=1.17" +packaging = "*" +pandas = "*" +pyarrow = ">=15.0.0" +pyyaml = ">=5.1" +requests = ">=2.32.2" +tqdm = ">=4.66.3" +xxhash = "*" + +[package.extras] +audio = ["soundfile (>=0.12.1)", "torch (>=2.7.0)", "torchcodec (>=0.4.0)"] +benchmarks = ["tensorflow (==2.12.0)", "torch (==2.0.1)", "transformers (==4.30.1)"] +dev = ["Pillow (>=9.4.0)", "absl-py", "aiohttp", "decorator", "elasticsearch (>=7.17.12,<8.0.0)", "faiss-cpu (>=1.8.0.post1)", "jax (>=0.3.14) ; sys_platform != \"win32\"", "jaxlib (>=0.3.14) ; sys_platform != \"win32\"", "joblib (<1.3.0)", "joblibspark", "lz4", "moto[server]", "numba (>=0.56.4)", "polars[timezone] (>=0.20.0)", "protobuf (<4.0.0)", "py7zr", "pyspark (>=3.4)", "pytest", "pytest-datadir", "pytest-xdist", "rarfile (>=4.0)", "ruff (>=0.3.0)", "soundfile (>=0.12.1)", "soundfile (>=0.12.1)", "sqlalchemy", "tensorflow (>=2.16.0) ; python_version >= \"3.10\" and sys_platform != \"win32\"", "tensorflow (>=2.6.0)", "tensorflow (>=2.6.0) ; python_version < \"3.10\" and sys_platform != \"win32\"", "tiktoken", "torch", "torch (>=2.0.0)", "torchcodec (>=0.4.0) ; sys_platform != \"win32\"", "torchdata", "transformers", "transformers (>=4.42.0)", "zstandard"] +docs = ["tensorflow (>=2.6.0)", "torch", "transformers"] +jax = ["jax (>=0.3.14)", "jaxlib (>=0.3.14)"] +pdfs = ["pdfplumber (>=0.11.4)"] +quality = ["ruff (>=0.3.0)"] +tensorflow = ["tensorflow (>=2.6.0)"] +tensorflow-gpu = ["tensorflow (>=2.6.0)"] +tests = ["Pillow (>=9.4.0)", "absl-py", "aiohttp", "decorator", "elasticsearch (>=7.17.12,<8.0.0)", "faiss-cpu (>=1.8.0.post1)", "jax (>=0.3.14) ; sys_platform != \"win32\"", "jaxlib (>=0.3.14) ; sys_platform != \"win32\"", "joblib (<1.3.0)", "joblibspark", "lz4", "moto[server]", "numba (>=0.56.4)", "polars[timezone] (>=0.20.0)", "protobuf (<4.0.0)", "py7zr", "pyspark (>=3.4)", "pytest", "pytest-datadir", "pytest-xdist", "rarfile (>=4.0)", "soundfile (>=0.12.1)", "soundfile (>=0.12.1)", "sqlalchemy", "tensorflow (>=2.16.0) ; python_version >= \"3.10\" and sys_platform != \"win32\"", "tensorflow (>=2.6.0) ; python_version < \"3.10\" and sys_platform != \"win32\"", "tiktoken", "torch (>=2.0.0)", "torchcodec (>=0.4.0) ; sys_platform != \"win32\"", "torchdata", "transformers (>=4.42.0)", "zstandard"] +tests-numpy2 = ["Pillow (>=9.4.0)", "absl-py", "aiohttp", "decorator", "elasticsearch (>=7.17.12,<8.0.0)", "jax (>=0.3.14) ; sys_platform != \"win32\"", "jaxlib (>=0.3.14) ; sys_platform != \"win32\"", "joblib (<1.3.0)", "joblibspark", "lz4", "moto[server]", "numba (>=0.56.4)", "polars[timezone] (>=0.20.0)", "protobuf (<4.0.0)", "py7zr", "pyspark (>=3.4)", "pytest", "pytest-datadir", "pytest-xdist", "rarfile (>=4.0)", "soundfile (>=0.12.1)", "soundfile (>=0.12.1)", "sqlalchemy", "tiktoken", "torch (>=2.0.0)", "torchcodec (>=0.4.0) ; sys_platform != \"win32\"", "torchdata", "transformers (>=4.42.0)", "zstandard"] +torch = ["torch"] +vision = ["Pillow (>=9.4.0)"] + +[[package]] +name = "dill" +version = "0.3.8" +description = "serialize all of Python" +optional = false +python-versions = ">=3.8" +groups = ["main", "dev"] +files = [ + {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, + {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] + +[[package]] +name = "distlib" +version = "0.4.0" +description = "Distribution utilities" +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, + {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, +] + +[[package]] +name = "docformatter" +version = "1.7.7" +description = "Formats docstrings to follow PEP 257" +optional = false +python-versions = "<4.0,>=3.9" +groups = ["dev"] +files = [ + {file = "docformatter-1.7.7-py3-none-any.whl", hash = "sha256:7af49f8a46346a77858f6651f431b882c503c2f4442c8b4524b920c863277834"}, + {file = "docformatter-1.7.7.tar.gz", hash = "sha256:ea0e1e8867e5af468dfc3f9e947b92230a55be9ec17cd1609556387bffac7978"}, +] + +[package.dependencies] +charset_normalizer = ">=3.0.0,<4.0.0" +untokenize = ">=0.1.1,<0.2.0" + +[package.extras] +tomli = ["tomli (>=2.0.0,<3.0.0) ; python_version < \"3.11\""] + +[[package]] +name = "docutils" +version = "0.21.2" +description = "Docutils -- Python Documentation Utilities" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, + {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, +] + +[[package]] +name = "eval-type-backport" +version = "0.2.2" +description = "Like `typing._eval_type`, but lets older Python versions use newer typing features." +optional = false +python-versions = ">=3.8" +groups = ["benchmarks"] +markers = "python_version == \"3.9\"" +files = [ + {file = "eval_type_backport-0.2.2-py3-none-any.whl", hash = "sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a"}, + {file = "eval_type_backport-0.2.2.tar.gz", hash = "sha256:f0576b4cf01ebb5bd358d02314d31846af5e07678387486e2c798af0e7d849c1"}, +] + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "exceptiongroup" +version = "1.3.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version < \"3.11\"" +files = [ + {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, + {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "execnet" +version = "2.1.1" +description = "execnet: rapid multi-Python deployment" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc"}, + {file = "execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3"}, +] + +[package.extras] +testing = ["hatch", "pre-commit", "pytest", "tox"] + +[[package]] +name = "filelock" +version = "3.19.1" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d"}, + {file = "filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58"}, +] + +[[package]] +name = "flake8" +version = "5.0.4" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.6.1" +groups = ["dev"] +files = [ + {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, + {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.9.0,<2.10.0" +pyflakes = ">=2.5.0,<2.6.0" + +[[package]] +name = "fonttools" +version = "4.59.2" +description = "Tools to manipulate font files" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "fonttools-4.59.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2a159e36ae530650acd13604f364b3a2477eff7408dcac6a640d74a3744d2514"}, + {file = "fonttools-4.59.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8bd733e47bf4c6dee2b2d8af7a1f7b0c091909b22dbb969a29b2b991e61e5ba4"}, + {file = "fonttools-4.59.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7bb32e0e33795e3b7795bb9b88cb6a9d980d3cbe26dd57642471be547708e17a"}, + {file = "fonttools-4.59.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cdcdf7aad4bab7fd0f2938624a5a84eb4893be269f43a6701b0720b726f24df0"}, + {file = "fonttools-4.59.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4d974312a9f405628e64f475b1f5015a61fd338f0a1b61d15c4822f97d6b045b"}, + {file = "fonttools-4.59.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:12dc4670e6e6cc4553e8de190f86a549e08ca83a036363115d94a2d67488831e"}, + {file = "fonttools-4.59.2-cp310-cp310-win32.whl", hash = "sha256:1603b85d5922042563eea518e272b037baf273b9a57d0f190852b0b075079000"}, + {file = "fonttools-4.59.2-cp310-cp310-win_amd64.whl", hash = "sha256:2543b81641ea5b8ddfcae7926e62aafd5abc604320b1b119e5218c014a7a5d3c"}, + {file = "fonttools-4.59.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:511946e8d7ea5c0d6c7a53c4cb3ee48eda9ab9797cd9bf5d95829a398400354f"}, + {file = "fonttools-4.59.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8e5e2682cf7be766d84f462ba8828d01e00c8751a8e8e7ce12d7784ccb69a30d"}, + {file = "fonttools-4.59.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5729e12a982dba3eeae650de48b06f3b9ddb51e9aee2fcaf195b7d09a96250e2"}, + {file = "fonttools-4.59.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c52694eae5d652361d59ecdb5a2246bff7cff13b6367a12da8499e9df56d148d"}, + {file = "fonttools-4.59.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f1f1bbc23ba1312bd8959896f46f667753b90216852d2a8cfa2d07e0cb234144"}, + {file = "fonttools-4.59.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1a1bfe5378962825dabe741720885e8b9ae9745ec7ecc4a5ec1f1ce59a6062bf"}, + {file = "fonttools-4.59.2-cp311-cp311-win32.whl", hash = "sha256:e937790f3c2c18a1cbc7da101550a84319eb48023a715914477d2e7faeaba570"}, + {file = "fonttools-4.59.2-cp311-cp311-win_amd64.whl", hash = "sha256:9836394e2f4ce5f9c0a7690ee93bd90aa1adc6b054f1a57b562c5d242c903104"}, + {file = "fonttools-4.59.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:82906d002c349cad647a7634b004825a7335f8159d0d035ae89253b4abf6f3ea"}, + {file = "fonttools-4.59.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a10c1bd7644dc58f8862d8ba0cf9fb7fef0af01ea184ba6ce3f50ab7dfe74d5a"}, + {file = "fonttools-4.59.2-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:738f31f23e0339785fd67652a94bc69ea49e413dfdb14dcb8c8ff383d249464e"}, + {file = "fonttools-4.59.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ec99f9bdfee9cdb4a9172f9e8fd578cce5feb231f598909e0aecf5418da4f25"}, + {file = "fonttools-4.59.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0476ea74161322e08c7a982f83558a2b81b491509984523a1a540baf8611cc31"}, + {file = "fonttools-4.59.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:95922a922daa1f77cc72611747c156cfb38030ead72436a2c551d30ecef519b9"}, + {file = "fonttools-4.59.2-cp312-cp312-win32.whl", hash = "sha256:39ad9612c6a622726a6a130e8ab15794558591f999673f1ee7d2f3d30f6a3e1c"}, + {file = "fonttools-4.59.2-cp312-cp312-win_amd64.whl", hash = "sha256:980fd7388e461b19a881d35013fec32c713ffea1fc37aef2f77d11f332dfd7da"}, + {file = "fonttools-4.59.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:381bde13216ba09489864467f6bc0c57997bd729abfbb1ce6f807ba42c06cceb"}, + {file = "fonttools-4.59.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f33839aa091f7eef4e9078f5b7ab1b8ea4b1d8a50aeaef9fdb3611bba80869ec"}, + {file = "fonttools-4.59.2-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6235fc06bcbdb40186f483ba9d5d68f888ea68aa3c8dac347e05a7c54346fbc8"}, + {file = "fonttools-4.59.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83ad6e5d06ef3a2884c4fa6384a20d6367b5cfe560e3b53b07c9dc65a7020e73"}, + {file = "fonttools-4.59.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d029804c70fddf90be46ed5305c136cae15800a2300cb0f6bba96d48e770dde0"}, + {file = "fonttools-4.59.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:95807a3b5e78f2714acaa26a33bc2143005cc05c0217b322361a772e59f32b89"}, + {file = "fonttools-4.59.2-cp313-cp313-win32.whl", hash = "sha256:b3ebda00c3bb8f32a740b72ec38537d54c7c09f383a4cfefb0b315860f825b08"}, + {file = "fonttools-4.59.2-cp313-cp313-win_amd64.whl", hash = "sha256:a72155928d7053bbde499d32a9c77d3f0f3d29ae72b5a121752481bcbd71e50f"}, + {file = "fonttools-4.59.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:d09e487d6bfbe21195801323ba95c91cb3523f0fcc34016454d4d9ae9eaa57fe"}, + {file = "fonttools-4.59.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:dec2f22486d7781087b173799567cffdcc75e9fb2f1c045f05f8317ccce76a3e"}, + {file = "fonttools-4.59.2-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1647201af10993090120da2e66e9526c4e20e88859f3e34aa05b8c24ded2a564"}, + {file = "fonttools-4.59.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47742c33fe65f41eabed36eec2d7313a8082704b7b808752406452f766c573fc"}, + {file = "fonttools-4.59.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:92ac2d45794f95d1ad4cb43fa07e7e3776d86c83dc4b9918cf82831518165b4b"}, + {file = "fonttools-4.59.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fa9ecaf2dcef8941fb5719e16322345d730f4c40599bbf47c9753de40eb03882"}, + {file = "fonttools-4.59.2-cp314-cp314-win32.whl", hash = "sha256:a8d40594982ed858780e18a7e4c80415af65af0f22efa7de26bdd30bf24e1e14"}, + {file = "fonttools-4.59.2-cp314-cp314-win_amd64.whl", hash = "sha256:9cde8b6a6b05f68516573523f2013a3574cb2c75299d7d500f44de82ba947b80"}, + {file = "fonttools-4.59.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:036cd87a2dbd7ef72f7b68df8314ced00b8d9973aee296f2464d06a836aeb9a9"}, + {file = "fonttools-4.59.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:14870930181493b1d740b6f25483e20185e5aea58aec7d266d16da7be822b4bb"}, + {file = "fonttools-4.59.2-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7ff58ea1eb8fc7e05e9a949419f031890023f8785c925b44d6da17a6a7d6e85d"}, + {file = "fonttools-4.59.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dee142b8b3096514c96ad9e2106bf039e2fe34a704c587585b569a36df08c3c"}, + {file = "fonttools-4.59.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8991bdbae39cf78bcc9cd3d81f6528df1f83f2e7c23ccf6f990fa1f0b6e19708"}, + {file = "fonttools-4.59.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:53c1a411b7690042535a4f0edf2120096a39a506adeb6c51484a232e59f2aa0c"}, + {file = "fonttools-4.59.2-cp314-cp314t-win32.whl", hash = "sha256:59d85088e29fa7a8f87d19e97a1beae2a35821ee48d8ef6d2c4f965f26cb9f8a"}, + {file = "fonttools-4.59.2-cp314-cp314t-win_amd64.whl", hash = "sha256:7ad5d8d8cc9e43cb438b3eb4a0094dd6d4088daa767b0a24d52529361fd4c199"}, + {file = "fonttools-4.59.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3cdf9d32690f0e235342055f0a6108eedfccf67b213b033bac747eb809809513"}, + {file = "fonttools-4.59.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:67f9640d6b31d66c0bc54bdbe8ed50983c755521c101576a25e377a8711e8207"}, + {file = "fonttools-4.59.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:464d15b58a9fd4304c728735fc1d42cd812fd9ebc27c45b18e78418efd337c28"}, + {file = "fonttools-4.59.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a039c38d5644c691eb53cd65360921338f54e44c90b4e764605711e046c926ee"}, + {file = "fonttools-4.59.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e4f5100e66ec307cce8b52fc03e379b5d1596e9cb8d8b19dfeeccc1e68d86c96"}, + {file = "fonttools-4.59.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:af6dbd463a3530256abf21f675ddf87646272bc48901803a185c49d06287fbf1"}, + {file = "fonttools-4.59.2-cp39-cp39-win32.whl", hash = "sha256:594a6fd2f8296583ac7babc4880c8deee7c4f05ab0141addc6bce8b8e367e996"}, + {file = "fonttools-4.59.2-cp39-cp39-win_amd64.whl", hash = "sha256:fc21c4a05226fd39715f66c1c28214862474db50df9f08fd1aa2f96698887bc3"}, + {file = "fonttools-4.59.2-py3-none-any.whl", hash = "sha256:8bd0f759020e87bb5d323e6283914d9bf4ae35a7307dafb2cbd1e379e720ad37"}, + {file = "fonttools-4.59.2.tar.gz", hash = "sha256:e72c0749b06113f50bcb80332364c6be83a9582d6e3db3fe0b280f996dc2ef22"}, +] + +[package.extras] +all = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\"", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0) ; python_version <= \"3.12\"", "xattr ; sys_platform == \"darwin\"", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\""] +lxml = ["lxml (>=4.0)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr ; sys_platform == \"darwin\""] +unicode = ["unicodedata2 (>=15.1.0) ; python_version <= \"3.12\""] +woff = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "zopfli (>=0.1.4)"] + +[[package]] +name = "frozenlist" +version = "1.7.0" +description = "A list-like structure which implements collections.abc.MutableSequence" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a"}, + {file = "frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61"}, + {file = "frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d"}, + {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e"}, + {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9"}, + {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c"}, + {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981"}, + {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615"}, + {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50"}, + {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa"}, + {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577"}, + {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59"}, + {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e"}, + {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd"}, + {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718"}, + {file = "frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e"}, + {file = "frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464"}, + {file = "frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a"}, + {file = "frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750"}, + {file = "frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd"}, + {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2"}, + {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f"}, + {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30"}, + {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98"}, + {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86"}, + {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae"}, + {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8"}, + {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31"}, + {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7"}, + {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5"}, + {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898"}, + {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56"}, + {file = "frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7"}, + {file = "frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d"}, + {file = "frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2"}, + {file = "frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb"}, + {file = "frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478"}, + {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8"}, + {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08"}, + {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4"}, + {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b"}, + {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e"}, + {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca"}, + {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df"}, + {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5"}, + {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025"}, + {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01"}, + {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08"}, + {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43"}, + {file = "frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3"}, + {file = "frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a"}, + {file = "frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee"}, + {file = "frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d"}, + {file = "frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43"}, + {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d"}, + {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee"}, + {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb"}, + {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f"}, + {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60"}, + {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00"}, + {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b"}, + {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c"}, + {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949"}, + {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca"}, + {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b"}, + {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e"}, + {file = "frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1"}, + {file = "frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba"}, + {file = "frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d"}, + {file = "frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d"}, + {file = "frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b"}, + {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146"}, + {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74"}, + {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1"}, + {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1"}, + {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384"}, + {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb"}, + {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c"}, + {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65"}, + {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3"}, + {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657"}, + {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104"}, + {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf"}, + {file = "frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81"}, + {file = "frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e"}, + {file = "frozenlist-1.7.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cea3dbd15aea1341ea2de490574a4a37ca080b2ae24e4b4f4b51b9057b4c3630"}, + {file = "frozenlist-1.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7d536ee086b23fecc36c2073c371572374ff50ef4db515e4e503925361c24f71"}, + {file = "frozenlist-1.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dfcebf56f703cb2e346315431699f00db126d158455e513bd14089d992101e44"}, + {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974c5336e61d6e7eb1ea5b929cb645e882aadab0095c5a6974a111e6479f8878"}, + {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c70db4a0ab5ab20878432c40563573229a7ed9241506181bba12f6b7d0dc41cb"}, + {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1137b78384eebaf70560a36b7b229f752fb64d463d38d1304939984d5cb887b6"}, + {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e793a9f01b3e8b5c0bc646fb59140ce0efcc580d22a3468d70766091beb81b35"}, + {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74739ba8e4e38221d2c5c03d90a7e542cb8ad681915f4ca8f68d04f810ee0a87"}, + {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e63344c4e929b1a01e29bc184bbb5fd82954869033765bfe8d65d09e336a677"}, + {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2ea2a7369eb76de2217a842f22087913cdf75f63cf1307b9024ab82dfb525938"}, + {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:836b42f472a0e006e02499cef9352ce8097f33df43baaba3e0a28a964c26c7d2"}, + {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e22b9a99741294b2571667c07d9f8cceec07cb92aae5ccda39ea1b6052ed4319"}, + {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:9a19e85cc503d958abe5218953df722748d87172f71b73cf3c9257a91b999890"}, + {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f22dac33bb3ee8fe3e013aa7b91dc12f60d61d05b7fe32191ffa84c3aafe77bd"}, + {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ccec739a99e4ccf664ea0775149f2749b8a6418eb5b8384b4dc0a7d15d304cb"}, + {file = "frozenlist-1.7.0-cp39-cp39-win32.whl", hash = "sha256:b3950f11058310008a87757f3eee16a8e1ca97979833239439586857bc25482e"}, + {file = "frozenlist-1.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:43a82fce6769c70f2f5a06248b614a7d268080a9d20f7457ef10ecee5af82b63"}, + {file = "frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e"}, + {file = "frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f"}, +] + +[[package]] +name = "fsspec" +version = "2025.3.0" +description = "File-system specification" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "fsspec-2025.3.0-py3-none-any.whl", hash = "sha256:efb87af3efa9103f94ca91a7f8cb7a4df91af9f74fc106c9c7ea0efd7277c1b3"}, + {file = "fsspec-2025.3.0.tar.gz", hash = "sha256:a935fd1ea872591f2b5148907d103488fc523295e6c64b835cfad8c3eca44972"}, +] + +[package.dependencies] +aiohttp = {version = "<4.0.0a0 || >4.0.0a0,<4.0.0a1 || >4.0.0a1", optional = true, markers = "extra == \"http\""} + +[package.extras] +abfs = ["adlfs"] +adl = ["adlfs"] +arrow = ["pyarrow (>=1)"] +dask = ["dask", "distributed"] +dev = ["pre-commit", "ruff"] +doc = ["numpydoc", "sphinx", "sphinx-design", "sphinx-rtd-theme", "yarl"] +dropbox = ["dropbox", "dropboxdrivefs", "requests"] +full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"] +fuse = ["fusepy"] +gcs = ["gcsfs"] +git = ["pygit2"] +github = ["requests"] +gs = ["gcsfs"] +gui = ["panel"] +hdfs = ["pyarrow (>=1)"] +http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"] +libarchive = ["libarchive-c"] +oci = ["ocifs"] +s3 = ["s3fs"] +sftp = ["paramiko"] +smb = ["smbprotocol"] +ssh = ["paramiko"] +test = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "numpy", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "requests"] +test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask[dataframe,test]", "moto[server] (>4,<5)", "pytest-timeout", "xarray"] +test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard"] +tqdm = ["tqdm"] + +[[package]] +name = "fuzzywuzzy" +version = "0.18.0" +description = "Fuzzy string matching in python" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "fuzzywuzzy-0.18.0-py2.py3-none-any.whl", hash = "sha256:928244b28db720d1e0ee7587acf660ea49d7e4c632569cad4f1cd7e68a5f0993"}, + {file = "fuzzywuzzy-0.18.0.tar.gz", hash = "sha256:45016e92264780e58972dca1b3d939ac864b78437422beecebb3095f8efd00e8"}, +] + +[package.extras] +speedup = ["python-levenshtein (>=0.12)"] + +[[package]] +name = "gitdb" +version = "4.0.12" +description = "Git Object Database" +optional = false +python-versions = ">=3.7" +groups = ["benchmarks"] +files = [ + {file = "gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf"}, + {file = "gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571"}, +] + +[package.dependencies] +smmap = ">=3.0.1,<6" + +[[package]] +name = "gitpython" +version = "3.1.45" +description = "GitPython is a Python library used to interact with Git repositories" +optional = false +python-versions = ">=3.7" +groups = ["benchmarks"] +files = [ + {file = "gitpython-3.1.45-py3-none-any.whl", hash = "sha256:8908cb2e02fb3b93b7eb0f2827125cb699869470432cc885f019b8fd0fccff77"}, + {file = "gitpython-3.1.45.tar.gz", hash = "sha256:85b0ee964ceddf211c41b9f27a49086010a190fd8132a24e21f362a4b36a791c"}, +] + +[package.dependencies] +gitdb = ">=4.0.1,<5" +typing-extensions = {version = ">=3.10.0.2", markers = "python_version < \"3.10\""} + +[package.extras] +doc = ["sphinx (>=7.1.2,<7.2)", "sphinx-autodoc-typehints", "sphinx_rtd_theme"] +test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock ; python_version < \"3.8\"", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions ; python_version < \"3.11\""] + +[[package]] +name = "hf-transfer" +version = "0.1.9" +description = "Speed up file transfers with the Hugging Face Hub." +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "hf_transfer-0.1.9-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:6e94e8822da79573c9b6ae4d6b2f847c59a7a06c5327d7db20751b68538dc4f6"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3ebc4ab9023414880c8b1d3c38174d1c9989eb5022d37e814fa91a3060123eb0"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8674026f21ed369aa2a0a4b46000aca850fc44cd2b54af33a172ce5325b4fc82"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a736dfbb2c84f5a2c975478ad200c0c8bfcb58a25a35db402678fb87ce17fa4"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:504b8427fd785dd8546d53b9fafe6e436bd7a3adf76b9dce556507650a7b4567"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c7fc1b85f4d0f76e452765d7648c9f4bfd0aedb9ced2ae1ebfece2d8cfaf8e2"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d991376f0eac70a60f0cbc95602aa708a6f7c8617f28b4945c1431d67b8e3c8"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e6ac4eddcd99575ed3735ed911ddf9d1697e2bd13aa3f0ad7e3904dd4863842e"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:57fd9880da1ee0f47250f735f791fab788f0aa1ee36afc49f761349869c8b4d9"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:5d561f0520f493c66b016d99ceabe69c23289aa90be38dd802d2aef279f15751"}, + {file = "hf_transfer-0.1.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a5b366d34cd449fe9b20ef25941e6eef0460a2f74e7389f02e673e1f88ebd538"}, + {file = "hf_transfer-0.1.9-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:e66acf91df4a8b72f60223059df3003062a5ae111757187ed1a06750a30e911b"}, + {file = "hf_transfer-0.1.9-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:8669dbcc7a3e2e8d61d42cd24da9c50d57770bd74b445c65123291ca842a7e7a"}, + {file = "hf_transfer-0.1.9-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8fd0167c4407a3bc4cdd0307e65ada2294ec04f1813d8a69a5243e379b22e9d8"}, + {file = "hf_transfer-0.1.9-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee8b10afedcb75f71091bcc197c526a6ebf5c58bbbadb34fdeee6160f55f619f"}, + {file = "hf_transfer-0.1.9-cp38-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5828057e313de59300dd1abb489444bc452efe3f479d3c55b31a8f680936ba42"}, + {file = "hf_transfer-0.1.9-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc6bd19e1cc177c66bdef15ef8636ad3bde79d5a4f608c158021153b4573509d"}, + {file = "hf_transfer-0.1.9-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdca9bfb89e6f8f281890cc61a8aff2d3cecaff7e1a4d275574d96ca70098557"}, + {file = "hf_transfer-0.1.9-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:89a23f58b7b7effbc047b8ca286f131b17728c99a9f972723323003ffd1bb916"}, + {file = "hf_transfer-0.1.9-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:dc7fff1345980d6c0ebb92c811d24afa4b98b3e07ed070c8e38cc91fd80478c5"}, + {file = "hf_transfer-0.1.9-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:1a6bd16c667ebe89a069ca163060127a794fa3a3525292c900b8c8cc47985b0d"}, + {file = "hf_transfer-0.1.9-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d2fde99d502093ade3ab1b53f80da18480e9902aa960dab7f74fb1b9e5bc5746"}, + {file = "hf_transfer-0.1.9-cp38-abi3-win32.whl", hash = "sha256:435cc3cdc8524ce57b074032b8fd76eed70a4224d2091232fa6a8cef8fd6803e"}, + {file = "hf_transfer-0.1.9-cp38-abi3-win_amd64.whl", hash = "sha256:16f208fc678911c37e11aa7b586bc66a37d02e636208f18b6bc53d29b5df40ad"}, + {file = "hf_transfer-0.1.9.tar.gz", hash = "sha256:035572865dab29d17e783fbf1e84cf1cb24f3fcf8f1b17db1cfc7fdf139f02bf"}, +] + +[[package]] +name = "hf-xet" +version = "1.1.9" +description = "Fast transfer of large files with the Hugging Face Hub." +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"arm64\" or platform_machine == \"aarch64\"" +files = [ + {file = "hf_xet-1.1.9-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:a3b6215f88638dd7a6ff82cb4e738dcbf3d863bf667997c093a3c990337d1160"}, + {file = "hf_xet-1.1.9-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:9b486de7a64a66f9a172f4b3e0dfe79c9f0a93257c501296a2521a13495a698a"}, + {file = "hf_xet-1.1.9-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4c5a840c2c4e6ec875ed13703a60e3523bc7f48031dfd750923b2a4d1a5fc3c"}, + {file = "hf_xet-1.1.9-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:96a6139c9e44dad1c52c52520db0fffe948f6bce487cfb9d69c125f254bb3790"}, + {file = "hf_xet-1.1.9-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ad1022e9a998e784c97b2173965d07fe33ee26e4594770b7785a8cc8f922cd95"}, + {file = "hf_xet-1.1.9-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:86754c2d6d5afb11b0a435e6e18911a4199262fe77553f8c50d75e21242193ea"}, + {file = "hf_xet-1.1.9-cp37-abi3-win_amd64.whl", hash = "sha256:5aad3933de6b725d61d51034e04174ed1dce7a57c63d530df0014dea15a40127"}, + {file = "hf_xet-1.1.9.tar.gz", hash = "sha256:c99073ce404462e909f1d5839b2d14a3827b8fe75ed8aed551ba6609c026c803"}, +] + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "huggingface-hub" +version = "0.34.4" +description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" +optional = false +python-versions = ">=3.8.0" +groups = ["main"] +files = [ + {file = "huggingface_hub-0.34.4-py3-none-any.whl", hash = "sha256:9b365d781739c93ff90c359844221beef048403f1bc1f1c123c191257c3c890a"}, + {file = "huggingface_hub-0.34.4.tar.gz", hash = "sha256:a4228daa6fb001be3f4f4bdaf9a0db00e1739235702848df00885c9b5742c85c"}, +] + +[package.dependencies] +filelock = "*" +fsspec = ">=2023.5.0" +hf-xet = {version = ">=1.1.3,<2.0.0", markers = "platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"arm64\" or platform_machine == \"aarch64\""} +packaging = ">=20.9" +pyyaml = ">=5.1" +requests = "*" +tqdm = ">=4.42.1" +typing-extensions = ">=3.7.4.3" + +[package.extras] +all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "libcst (>=1.4.0)", "mypy (==1.15.0) ; python_version >= \"3.9\"", "mypy (>=1.14.1,<1.15.0) ; python_version == \"3.8\"", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.9.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +cli = ["InquirerPy (==0.3.4)"] +dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "libcst (>=1.4.0)", "mypy (==1.15.0) ; python_version >= \"3.9\"", "mypy (>=1.14.1,<1.15.0) ; python_version == \"3.8\"", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.9.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"] +fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"] +hf-transfer = ["hf-transfer (>=0.1.4)"] +hf-xet = ["hf-xet (>=1.1.2,<2.0.0)"] +inference = ["aiohttp"] +mcp = ["aiohttp", "mcp (>=1.8.0)", "typer"] +oauth = ["authlib (>=1.3.2)", "fastapi", "httpx", "itsdangerous"] +quality = ["libcst (>=1.4.0)", "mypy (==1.15.0) ; python_version >= \"3.9\"", "mypy (>=1.14.1,<1.15.0) ; python_version == \"3.8\"", "ruff (>=0.9.0)"] +tensorflow = ["graphviz", "pydot", "tensorflow"] +tensorflow-testing = ["keras (<3.0)", "tensorflow"] +testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"] +torch = ["safetensors[torch]", "torch"] +typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"] + +[[package]] +name = "identify" +version = "2.6.13" +description = "File identification library for Python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "identify-2.6.13-py2.py3-none-any.whl", hash = "sha256:60381139b3ae39447482ecc406944190f690d4a2997f2584062089848361b33b"}, + {file = "identify-2.6.13.tar.gz", hash = "sha256:da8d6c828e773620e13bfa86ea601c5a5310ba4bcd65edf378198b56a1f9fb32"}, +] + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +groups = ["main", "benchmarks", "docs"] +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + +[[package]] +name = "imagesize" +version = "1.4.1" +description = "Getting image size from png/jpeg/jpeg2000/gif file" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["docs"] +files = [ + {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, + {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, +] + +[[package]] +name = "importlib-metadata" +version = "8.7.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.9" +groups = ["main", "docs"] +files = [ + {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"}, + {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"}, +] +markers = {main = "python_version == \"3.9\" and platform_system == \"Linux\" and platform_machine == \"x86_64\"", docs = "python_version == \"3.9\""} + +[package.dependencies] +zipp = ">=3.20" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +perf = ["ipython"] +test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] + +[[package]] +name = "importlib-resources" +version = "6.5.2" +description = "Read resources from Python packages" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version == \"3.9\"" +files = [ + {file = "importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec"}, + {file = "importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c"}, +] + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.test (>=5.4)", "pytest (>=6,!=8.1.*)", "zipp (>=3.17)"] +type = ["pytest-mypy"] + +[[package]] +name = "iniconfig" +version = "2.1.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, +] + +[[package]] +name = "isort" +version = "5.12.0" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.8.0" +groups = ["dev"] +files = [ + {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, + {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, +] + +[package.extras] +colors = ["colorama (>=0.4.3)"] +pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] + +[[package]] +name = "jieba" +version = "0.42.1" +description = "Chinese Words Segmentation Utilities" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "jieba-0.42.1.tar.gz", hash = "sha256:055ca12f62674fafed09427f176506079bc135638a14e23e25be909131928db2"}, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +groups = ["main", "docs"] +files = [ + {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, + {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "joblib" +version = "1.5.2" +description = "Lightweight pipelining with Python functions" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241"}, + {file = "joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55"}, +] + +[[package]] +name = "kiwisolver" +version = "1.4.7" +description = "A fast implementation of the Cassowary constraint solver" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version < \"3.11\"" +files = [ + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8a9c83f75223d5e48b0bc9cb1bf2776cf01563e00ade8775ffe13b0b6e1af3a6"}, + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58370b1ffbd35407444d57057b57da5d6549d2d854fa30249771775c63b5fe17"}, + {file = "kiwisolver-1.4.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aa0abdf853e09aff551db11fce173e2177d00786c688203f52c87ad7fcd91ef9"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d53103597a252fb3ab8b5845af04c7a26d5e7ea8122303dd7a021176a87e8b9"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:88f17c5ffa8e9462fb79f62746428dd57b46eb931698e42e990ad63103f35e6c"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a9ca9c710d598fd75ee5de59d5bda2684d9db36a9f50b6125eaea3969c2599"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f4d742cb7af1c28303a51b7a27aaee540e71bb8e24f68c736f6f2ffc82f2bf05"}, + {file = "kiwisolver-1.4.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e28c7fea2196bf4c2f8d46a0415c77a1c480cc0724722f23d7410ffe9842c407"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e968b84db54f9d42046cf154e02911e39c0435c9801681e3fc9ce8a3c4130278"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0c18ec74c0472de033e1bebb2911c3c310eef5649133dd0bedf2a169a1b269e5"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8f0ea6da6d393d8b2e187e6a5e3fb81f5862010a40c3945e2c6d12ae45cfb2ad"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f106407dda69ae456dd1227966bf445b157ccc80ba0dff3802bb63f30b74e895"}, + {file = "kiwisolver-1.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:84ec80df401cfee1457063732d90022f93951944b5b58975d34ab56bb150dfb3"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win32.whl", hash = "sha256:71bb308552200fb2c195e35ef05de12f0c878c07fc91c270eb3d6e41698c3bcc"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:44756f9fd339de0fb6ee4f8c1696cfd19b2422e0d70b4cefc1cc7f1f64045a8c"}, + {file = "kiwisolver-1.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:78a42513018c41c2ffd262eb676442315cbfe3c44eed82385c2ed043bc63210a"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d2b0e12a42fb4e72d509fc994713d099cbb15ebf1103545e8a45f14da2dfca54"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2a8781ac3edc42ea4b90bc23e7d37b665d89423818e26eb6df90698aa2287c95"}, + {file = "kiwisolver-1.4.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46707a10836894b559e04b0fd143e343945c97fd170d69a2d26d640b4e297935"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef97b8df011141c9b0f6caf23b29379f87dd13183c978a30a3c546d2c47314cb"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ab58c12a2cd0fc769089e6d38466c46d7f76aced0a1f54c77652446733d2d02"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:803b8e1459341c1bb56d1c5c010406d5edec8a0713a0945851290a7930679b51"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9a9e8a507420fe35992ee9ecb302dab68550dedc0da9e2880dd88071c5fb052"}, + {file = "kiwisolver-1.4.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18077b53dc3bb490e330669a99920c5e6a496889ae8c63b58fbc57c3d7f33a18"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6af936f79086a89b3680a280c47ea90b4df7047b5bdf3aa5c524bbedddb9e545"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3abc5b19d24af4b77d1598a585b8a719beb8569a71568b66f4ebe1fb0449460b"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:933d4de052939d90afbe6e9d5273ae05fb836cc86c15b686edd4b3560cc0ee36"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:65e720d2ab2b53f1f72fb5da5fb477455905ce2c88aaa671ff0a447c2c80e8e3"}, + {file = "kiwisolver-1.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3bf1ed55088f214ba6427484c59553123fdd9b218a42bbc8c6496d6754b1e523"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win32.whl", hash = "sha256:4c00336b9dd5ad96d0a558fd18a8b6f711b7449acce4c157e7343ba92dd0cf3d"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:929e294c1ac1e9f615c62a4e4313ca1823ba37326c164ec720a803287c4c499b"}, + {file = "kiwisolver-1.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:e33e8fbd440c917106b237ef1a2f1449dfbb9b6f6e1ce17c94cd6a1e0d438376"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5360cc32706dab3931f738d3079652d20982511f7c0ac5711483e6eab08efff2"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942216596dc64ddb25adb215c3c783215b23626f8d84e8eff8d6d45c3f29f75a"}, + {file = "kiwisolver-1.4.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:48b571ecd8bae15702e4f22d3ff6a0f13e54d3d00cd25216d5e7f658242065ee"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad42ba922c67c5f219097b28fae965e10045ddf145d2928bfac2eb2e17673640"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:612a10bdae23404a72941a0fc8fa2660c6ea1217c4ce0dbcab8a8f6543ea9e7f"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e838bba3a3bac0fe06d849d29772eb1afb9745a59710762e4ba3f4cb8424483"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22f499f6157236c19f4bbbd472fa55b063db77a16cd74d49afe28992dff8c258"}, + {file = "kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693902d433cf585133699972b6d7c42a8b9f8f826ebcaf0132ff55200afc599e"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4e77f2126c3e0b0d055f44513ed349038ac180371ed9b52fe96a32aa071a5107"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:657a05857bda581c3656bfc3b20e353c232e9193eb167766ad2dc58b56504948"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4bfa75a048c056a411f9705856abfc872558e33c055d80af6a380e3658766038"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:34ea1de54beef1c104422d210c47c7d2a4999bdecf42c7b5718fbe59a4cac383"}, + {file = "kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:90da3b5f694b85231cf93586dad5e90e2d71b9428f9aad96952c99055582f520"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win32.whl", hash = "sha256:18e0cca3e008e17fe9b164b55735a325140a5a35faad8de92dd80265cd5eb80b"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:58cb20602b18f86f83a5c87d3ee1c766a79c0d452f8def86d925e6c60fbf7bfb"}, + {file = "kiwisolver-1.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:f5a8b53bdc0b3961f8b6125e198617c40aeed638b387913bf1ce78afb1b0be2a"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2e6039dcbe79a8e0f044f1c39db1986a1b8071051efba3ee4d74f5b365f5226e"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a1ecf0ac1c518487d9d23b1cd7139a6a65bc460cd101ab01f1be82ecf09794b6"}, + {file = "kiwisolver-1.4.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ab9ccab2b5bd5702ab0803676a580fffa2aa178c2badc5557a84cc943fcf750"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f816dd2277f8d63d79f9c8473a79fe54047bc0467754962840782c575522224d"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf8bcc23ceb5a1b624572a1623b9f79d2c3b337c8c455405ef231933a10da379"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dea0bf229319828467d7fca8c7c189780aa9ff679c94539eed7532ebe33ed37c"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c06a4c7cf15ec739ce0e5971b26c93638730090add60e183530d70848ebdd34"}, + {file = "kiwisolver-1.4.7-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:913983ad2deb14e66d83c28b632fd35ba2b825031f2fa4ca29675e665dfecbe1"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5337ec7809bcd0f424c6b705ecf97941c46279cf5ed92311782c7c9c2026f07f"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4c26ed10c4f6fa6ddb329a5120ba3b6db349ca192ae211e882970bfc9d91420b"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c619b101e6de2222c1fcb0531e1b17bbffbe54294bfba43ea0d411d428618c27"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:073a36c8273647592ea332e816e75ef8da5c303236ec0167196793eb1e34657a"}, + {file = "kiwisolver-1.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3ce6b2b0231bda412463e152fc18335ba32faf4e8c23a754ad50ffa70e4091ee"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win32.whl", hash = "sha256:f4c9aee212bc89d4e13f58be11a56cc8036cabad119259d12ace14b34476fd07"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:8a3ec5aa8e38fc4c8af308917ce12c536f1c88452ce554027e55b22cbbfbff76"}, + {file = "kiwisolver-1.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:76c8094ac20ec259471ac53e774623eb62e6e1f56cd8690c67ce6ce4fcb05650"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5d5abf8f8ec1f4e22882273c423e16cae834c36856cac348cfbfa68e01c40f3a"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:aeb3531b196ef6f11776c21674dba836aeea9d5bd1cf630f869e3d90b16cfade"}, + {file = "kiwisolver-1.4.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7d755065e4e866a8086c9bdada157133ff466476a2ad7861828e17b6026e22c"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08471d4d86cbaec61f86b217dd938a83d85e03785f51121e791a6e6689a3be95"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bbfcb7165ce3d54a3dfbe731e470f65739c4c1f85bb1018ee912bae139e263b"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d34eb8494bea691a1a450141ebb5385e4b69d38bb8403b5146ad279f4b30fa3"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9242795d174daa40105c1d86aba618e8eab7bf96ba8c3ee614da8302a9f95503"}, + {file = "kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a0f64a48bb81af7450e641e3fe0b0394d7381e342805479178b3d335d60ca7cf"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8e045731a5416357638d1700927529e2b8ab304811671f665b225f8bf8d8f933"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4322872d5772cae7369f8351da1edf255a604ea7087fe295411397d0cfd9655e"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e1631290ee9271dffe3062d2634c3ecac02c83890ada077d225e081aca8aab89"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:edcfc407e4eb17e037bca59be0e85a2031a2ac87e4fed26d3e9df88b4165f92d"}, + {file = "kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4d05d81ecb47d11e7f8932bd8b61b720bf0b41199358f3f5e36d38e28f0532c5"}, + {file = "kiwisolver-1.4.7-cp38-cp38-win32.whl", hash = "sha256:b38ac83d5f04b15e515fd86f312479d950d05ce2368d5413d46c088dda7de90a"}, + {file = "kiwisolver-1.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:d83db7cde68459fc803052a55ace60bea2bae361fc3b7a6d5da07e11954e4b09"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3f9362ecfca44c863569d3d3c033dbe8ba452ff8eed6f6b5806382741a1334bd"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e8df2eb9b2bac43ef8b082e06f750350fbbaf2887534a5be97f6cf07b19d9583"}, + {file = "kiwisolver-1.4.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f32d6edbc638cde7652bd690c3e728b25332acbadd7cad670cc4a02558d9c417"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e2e6c39bd7b9372b0be21456caab138e8e69cc0fc1190a9dfa92bd45a1e6e904"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dda56c24d869b1193fcc763f1284b9126550eaf84b88bbc7256e15028f19188a"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79849239c39b5e1fd906556c474d9b0439ea6792b637511f3fe3a41158d89ca8"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5e3bc157fed2a4c02ec468de4ecd12a6e22818d4f09cde2c31ee3226ffbefab2"}, + {file = "kiwisolver-1.4.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3da53da805b71e41053dc670f9a820d1157aae77b6b944e08024d17bcd51ef88"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8705f17dfeb43139a692298cb6637ee2e59c0194538153e83e9ee0c75c2eddde"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:82a5c2f4b87c26bb1a0ef3d16b5c4753434633b83d365cc0ddf2770c93829e3c"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce8be0466f4c0d585cdb6c1e2ed07232221df101a4c6f28821d2aa754ca2d9e2"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:409afdfe1e2e90e6ee7fc896f3df9a7fec8e793e58bfa0d052c8a82f99c37abb"}, + {file = "kiwisolver-1.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5b9c3f4ee0b9a439d2415012bd1b1cc2df59e4d6a9939f4d669241d30b414327"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win32.whl", hash = "sha256:a79ae34384df2b615eefca647a2873842ac3b596418032bef9a7283675962644"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:cf0438b42121a66a3a667de17e779330fc0f20b0d97d59d2f2121e182b0505e4"}, + {file = "kiwisolver-1.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:764202cc7e70f767dab49e8df52c7455e8de0df5d858fa801a11aa0d882ccf3f"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:94252291e3fe68001b1dd747b4c0b3be12582839b95ad4d1b641924d68fd4643"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5b7dfa3b546da08a9f622bb6becdb14b3e24aaa30adba66749d38f3cc7ea9706"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd3de6481f4ed8b734da5df134cd5a6a64fe32124fe83dde1e5b5f29fe30b1e6"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a91b5f9f1205845d488c928e8570dcb62b893372f63b8b6e98b863ebd2368ff2"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40fa14dbd66b8b8f470d5fc79c089a66185619d31645f9b0773b88b19f7223c4"}, + {file = "kiwisolver-1.4.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:eb542fe7933aa09d8d8f9d9097ef37532a7df6497819d16efe4359890a2f417a"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bfa1acfa0c54932d5607e19a2c24646fb4c1ae2694437789129cf099789a3b00"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:eee3ea935c3d227d49b4eb85660ff631556841f6e567f0f7bda972df6c2c9935"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f3160309af4396e0ed04db259c3ccbfdc3621b5559b5453075e5de555e1f3a1b"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a17f6a29cf8935e587cc8a4dbfc8368c55edc645283db0ce9801016f83526c2d"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10849fb2c1ecbfae45a693c070e0320a91b35dd4bcf58172c023b994283a124d"}, + {file = "kiwisolver-1.4.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ac542bf38a8a4be2dc6b15248d36315ccc65f0743f7b1a76688ffb6b5129a5c2"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8b01aac285f91ca889c800042c35ad3b239e704b150cfd3382adfc9dcc780e39"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:48be928f59a1f5c8207154f935334d374e79f2b5d212826307d072595ad76a2e"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f37cfe618a117e50d8c240555331160d73d0411422b59b5ee217843d7b693608"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:599b5c873c63a1f6ed7eead644a8a380cfbdf5db91dcb6f85707aaab213b1674"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:801fa7802e5cfabe3ab0c81a34c323a319b097dfb5004be950482d882f3d7225"}, + {file = "kiwisolver-1.4.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0c6c43471bc764fad4bc99c5c2d6d16a676b1abf844ca7c8702bdae92df01ee0"}, + {file = "kiwisolver-1.4.7.tar.gz", hash = "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60"}, +] + +[[package]] +name = "kiwisolver" +version = "1.4.9" +description = "A fast implementation of the Cassowary constraint solver" +optional = false +python-versions = ">=3.10" +groups = ["main"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b"}, + {file = "kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f"}, + {file = "kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf"}, + {file = "kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9"}, + {file = "kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415"}, + {file = "kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b"}, + {file = "kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154"}, + {file = "kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48"}, + {file = "kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220"}, + {file = "kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586"}, + {file = "kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634"}, + {file = "kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611"}, + {file = "kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536"}, + {file = "kiwisolver-1.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eb14a5da6dc7642b0f3a18f13654847cd8b7a2550e2645a5bda677862b03ba16"}, + {file = "kiwisolver-1.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39a219e1c81ae3b103643d2aedb90f1ef22650deb266ff12a19e7773f3e5f089"}, + {file = "kiwisolver-1.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2405a7d98604b87f3fc28b1716783534b1b4b8510d8142adca34ee0bc3c87543"}, + {file = "kiwisolver-1.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dc1ae486f9abcef254b5618dfb4113dd49f94c68e3e027d03cf0143f3f772b61"}, + {file = "kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a1f570ce4d62d718dce3f179ee78dac3b545ac16c0c04bb363b7607a949c0d1"}, + {file = "kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb27e7b78d716c591e88e0a09a2139c6577865d7f2e152488c2cc6257f460872"}, + {file = "kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:15163165efc2f627eb9687ea5f3a28137217d217ac4024893d753f46bce9de26"}, + {file = "kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bdee92c56a71d2b24c33a7d4c2856bd6419d017e08caa7802d2963870e315028"}, + {file = "kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:412f287c55a6f54b0650bd9b6dce5aceddb95864a1a90c87af16979d37c89771"}, + {file = "kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2c93f00dcba2eea70af2be5f11a830a742fe6b579a1d4e00f47760ef13be247a"}, + {file = "kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f117e1a089d9411663a3207ba874f31be9ac8eaa5b533787024dc07aeb74f464"}, + {file = "kiwisolver-1.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:be6a04e6c79819c9a8c2373317d19a96048e5a3f90bec587787e86a1153883c2"}, + {file = "kiwisolver-1.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:0ae37737256ba2de764ddc12aed4956460277f00c4996d51a197e72f62f5eec7"}, + {file = "kiwisolver-1.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ac5a486ac389dddcc5bef4f365b6ae3ffff2c433324fb38dd35e3fab7c957999"}, + {file = "kiwisolver-1.4.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2ba92255faa7309d06fe44c3a4a97efe1c8d640c2a79a5ef728b685762a6fd2"}, + {file = "kiwisolver-1.4.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a2899935e724dd1074cb568ce7ac0dce28b2cd6ab539c8e001a8578eb106d14"}, + {file = "kiwisolver-1.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f6008a4919fdbc0b0097089f67a1eb55d950ed7e90ce2cc3e640abadd2757a04"}, + {file = "kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67bb8b474b4181770f926f7b7d2f8c0248cbcb78b660fdd41a47054b28d2a752"}, + {file = "kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2327a4a30d3ee07d2fbe2e7933e8a37c591663b96ce42a00bc67461a87d7df77"}, + {file = "kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a08b491ec91b1d5053ac177afe5290adacf1f0f6307d771ccac5de30592d198"}, + {file = "kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8fc5c867c22b828001b6a38d2eaeb88160bf5783c6cb4a5e440efc981ce286d"}, + {file = "kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3b3115b2581ea35bb6d1f24a4c90af37e5d9b49dcff267eeed14c3893c5b86ab"}, + {file = "kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858e4c22fb075920b96a291928cb7dea5644e94c0ee4fcd5af7e865655e4ccf2"}, + {file = "kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed0fecd28cc62c54b262e3736f8bb2512d8dcfdc2bcf08be5f47f96bf405b145"}, + {file = "kiwisolver-1.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:f68208a520c3d86ea51acf688a3e3002615a7f0238002cccc17affecc86a8a54"}, + {file = "kiwisolver-1.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:2c1a4f57df73965f3f14df20b80ee29e6a7930a57d2d9e8491a25f676e197c60"}, + {file = "kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8"}, + {file = "kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2"}, + {file = "kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f"}, + {file = "kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098"}, + {file = "kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed"}, + {file = "kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525"}, + {file = "kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78"}, + {file = "kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b"}, + {file = "kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799"}, + {file = "kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3"}, + {file = "kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c"}, + {file = "kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d"}, + {file = "kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07"}, + {file = "kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c"}, + {file = "kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386"}, + {file = "kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552"}, + {file = "kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3"}, + {file = "kiwisolver-1.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58"}, + {file = "kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4"}, + {file = "kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df"}, + {file = "kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6"}, + {file = "kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5"}, + {file = "kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf"}, + {file = "kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5"}, + {file = "kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce"}, + {file = "kiwisolver-1.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7"}, + {file = "kiwisolver-1.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891"}, + {file = "kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32"}, + {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527"}, + {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771"}, + {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e"}, + {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9"}, + {file = "kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb"}, + {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:720e05574713db64c356e86732c0f3c5252818d05f9df320f0ad8380641acea5"}, + {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:17680d737d5335b552994a2008fab4c851bcd7de33094a82067ef3a576ff02fa"}, + {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85b5352f94e490c028926ea567fc569c52ec79ce131dadb968d3853e809518c2"}, + {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:464415881e4801295659462c49461a24fb107c140de781d55518c4b80cb6790f"}, + {file = "kiwisolver-1.4.9-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fb940820c63a9590d31d88b815e7a3aa5915cad3ce735ab45f0c730b39547de1"}, + {file = "kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d"}, +] + +[[package]] +name = "lazy-object-proxy" +version = "1.12.0" +description = "A fast and thorough lazy object proxy." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "lazy_object_proxy-1.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61d5e3310a4aa5792c2b599a7a78ccf8687292c8eb09cf187cca8f09cf6a7519"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1ca33565f698ac1aece152a10f432415d1a2aa9a42dfe23e5ba2bc255ab91f6"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01c7819a410f7c255b20799b65d36b414379a30c6f1684c7bd7eb6777338c1b"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:029d2b355076710505c9545aef5ab3f750d89779310e26ddf2b7b23f6ea03cd8"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc6e3614eca88b1c8a625fc0a47d0d745e7c3255b21dac0e30b3037c5e3deeb8"}, + {file = "lazy_object_proxy-1.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:be5fe974e39ceb0d6c9db0663c0464669cf866b2851c73971409b9566e880eab"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1cf69cd1a6c7fe2dbcc3edaa017cf010f4192e53796538cc7d5e1fedbfa4bcff"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:efff4375a8c52f55a145dc8487a2108c2140f0bec4151ab4e1843e52eb9987ad"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1192e8c2f1031a6ff453ee40213afa01ba765b3dc861302cd91dbdb2e2660b00"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3605b632e82a1cbc32a1e5034278a64db555b3496e0795723ee697006b980508"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a61095f5d9d1a743e1e20ec6d6db6c2ca511961777257ebd9b288951b23b44fa"}, + {file = "lazy_object_proxy-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:997b1d6e10ecc6fb6fe0f2c959791ae59599f41da61d652f6c903d1ee58b7370"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8ee0d6027b760a11cc18281e702c0309dd92da458a74b4c15025d7fc490deede"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4ab2c584e3cc8be0dfca422e05ad30a9abe3555ce63e9ab7a559f62f8dbc6ff9"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:14e348185adbd03ec17d051e169ec45686dcd840a3779c9d4c10aabe2ca6e1c0"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4fcbe74fb85df8ba7825fa05eddca764138da752904b378f0ae5ab33a36c308"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:563d2ec8e4d4b68ee7848c5ab4d6057a6d703cb7963b342968bb8758dda33a23"}, + {file = "lazy_object_proxy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:53c7fd99eb156bbb82cbc5d5188891d8fdd805ba6c1e3b92b90092da2a837073"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:86fd61cb2ba249b9f436d789d1356deae69ad3231dc3c0f17293ac535162672e"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:81d1852fb30fab81696f93db1b1e55a5d1ff7940838191062f5f56987d5fcc3e"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be9045646d83f6c2664c1330904b245ae2371b5c57a3195e4028aedc9f999655"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:67f07ab742f1adfb3966c40f630baaa7902be4222a17941f3d85fd1dae5565ff"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:75ba769017b944fcacbf6a80c18b2761a1795b03f8899acdad1f1c39db4409be"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:7b22c2bbfb155706b928ac4d74c1a63ac8552a55ba7fff4445155523ea4067e1"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4a79b909aa16bde8ae606f06e6bbc9d3219d2e57fb3e0076e17879072b742c65"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:338ab2f132276203e404951205fe80c3fd59429b3a724e7b662b2eb539bb1be9"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c40b3c9faee2e32bfce0df4ae63f4e73529766893258eca78548bac801c8f66"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:717484c309df78cedf48396e420fa57fc8a2b1f06ea889df7248fdd156e58847"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a6b7ea5ea1ffe15059eb44bcbcb258f97bcb40e139b88152c40d07b1a1dfc9ac"}, + {file = "lazy_object_proxy-1.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:08c465fb5cd23527512f9bd7b4c7ba6cec33e28aad36fbbe46bf7b858f9f3f7f"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c9defba70ab943f1df98a656247966d7729da2fe9c2d5d85346464bf320820a3"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6763941dbf97eea6b90f5b06eb4da9418cc088fce0e3883f5816090f9afcde4a"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fdc70d81235fc586b9e3d1aeef7d1553259b62ecaae9db2167a5d2550dcc391a"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0a83c6f7a6b2bfc11ef3ed67f8cbe99f8ff500b05655d8e7df9aab993a6abc95"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:256262384ebd2a77b023ad02fbcc9326282bcfd16484d5531154b02bc304f4c5"}, + {file = "lazy_object_proxy-1.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:7601ec171c7e8584f8ff3f4e440aa2eebf93e854f04639263875b8c2971f819f"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ae575ad9b674d0029fc077c5231b3bc6b433a3d1a62a8c363df96974b5534728"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31020c84005d3daa4cc0fa5a310af2066efe6b0d82aeebf9ab199292652ff036"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:800f32b00a47c27446a2b767df7538e6c66a3488632c402b4fb2224f9794f3c0"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:15400b18893f345857b9e18b9bd87bd06aba84af6ed086187add70aeaa3f93f1"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3d3964fbd326578bcdfffd017ef101b6fb0484f34e731fe060ba9b8816498c36"}, + {file = "lazy_object_proxy-1.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:424a8ab6695400845c39f13c685050eab69fa0bbac5790b201cd27375e5e41d7"}, + {file = "lazy_object_proxy-1.12.0-pp39.pp310.pp311.graalpy311-none-any.whl", hash = "sha256:c3b2e0af1f7f77c4263759c4824316ce458fabe0fceadcd24ef8ca08b2d1e402"}, + {file = "lazy_object_proxy-1.12.0.tar.gz", hash = "sha256:1f5a462d92fd0cfb82f1fab28b51bfb209fabbe6aabf7f0d51472c0c124c0c61"}, +] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +groups = ["dev", "docs"] +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "markupsafe" +version = "3.0.2" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.9" +groups = ["main", "docs"] +files = [ + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, +] + +[[package]] +name = "matplotlib" +version = "3.9.4" +description = "Python plotting package" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version < \"3.11\"" +files = [ + {file = "matplotlib-3.9.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c5fdd7abfb706dfa8d307af64a87f1a862879ec3cd8d0ec8637458f0885b9c50"}, + {file = "matplotlib-3.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d89bc4e85e40a71d1477780366c27fb7c6494d293e1617788986f74e2a03d7ff"}, + {file = "matplotlib-3.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddf9f3c26aae695c5daafbf6b94e4c1a30d6cd617ba594bbbded3b33a1fcfa26"}, + {file = "matplotlib-3.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18ebcf248030173b59a868fda1fe42397253f6698995b55e81e1f57431d85e50"}, + {file = "matplotlib-3.9.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:974896ec43c672ec23f3f8c648981e8bc880ee163146e0312a9b8def2fac66f5"}, + {file = "matplotlib-3.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:4598c394ae9711cec135639374e70871fa36b56afae17bdf032a345be552a88d"}, + {file = "matplotlib-3.9.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d4dd29641d9fb8bc4492420c5480398dd40a09afd73aebe4eb9d0071a05fbe0c"}, + {file = "matplotlib-3.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30e5b22e8bcfb95442bf7d48b0d7f3bdf4a450cbf68986ea45fca3d11ae9d099"}, + {file = "matplotlib-3.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bb0030d1d447fd56dcc23b4c64a26e44e898f0416276cac1ebc25522e0ac249"}, + {file = "matplotlib-3.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aca90ed222ac3565d2752b83dbb27627480d27662671e4d39da72e97f657a423"}, + {file = "matplotlib-3.9.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a181b2aa2906c608fcae72f977a4a2d76e385578939891b91c2550c39ecf361e"}, + {file = "matplotlib-3.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:1f6882828231eca17f501c4dcd98a05abb3f03d157fbc0769c6911fe08b6cfd3"}, + {file = "matplotlib-3.9.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:dfc48d67e6661378a21c2983200a654b72b5c5cdbd5d2cf6e5e1ece860f0cc70"}, + {file = "matplotlib-3.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:47aef0fab8332d02d68e786eba8113ffd6f862182ea2999379dec9e237b7e483"}, + {file = "matplotlib-3.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fba1f52c6b7dc764097f52fd9ab627b90db452c9feb653a59945de16752e965f"}, + {file = "matplotlib-3.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:173ac3748acaac21afcc3fa1633924609ba1b87749006bc25051c52c422a5d00"}, + {file = "matplotlib-3.9.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320edea0cadc07007765e33f878b13b3738ffa9745c5f707705692df70ffe0e0"}, + {file = "matplotlib-3.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a4a4cfc82330b27042a7169533da7991e8789d180dd5b3daeaee57d75cd5a03b"}, + {file = "matplotlib-3.9.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:37eeffeeca3c940985b80f5b9a7b95ea35671e0e7405001f249848d2b62351b6"}, + {file = "matplotlib-3.9.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3e7465ac859ee4abcb0d836137cd8414e7bb7ad330d905abced457217d4f0f45"}, + {file = "matplotlib-3.9.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4c12302c34afa0cf061bea23b331e747e5e554b0fa595c96e01c7b75bc3b858"}, + {file = "matplotlib-3.9.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b8c97917f21b75e72108b97707ba3d48f171541a74aa2a56df7a40626bafc64"}, + {file = "matplotlib-3.9.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0229803bd7e19271b03cb09f27db76c918c467aa4ce2ae168171bc67c3f508df"}, + {file = "matplotlib-3.9.4-cp313-cp313-win_amd64.whl", hash = "sha256:7c0d8ef442ebf56ff5e206f8083d08252ee738e04f3dc88ea882853a05488799"}, + {file = "matplotlib-3.9.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a04c3b00066a688834356d196136349cb32f5e1003c55ac419e91585168b88fb"}, + {file = "matplotlib-3.9.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:04c519587f6c210626741a1e9a68eefc05966ede24205db8982841826af5871a"}, + {file = "matplotlib-3.9.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308afbf1a228b8b525fcd5cec17f246bbbb63b175a3ef6eb7b4d33287ca0cf0c"}, + {file = "matplotlib-3.9.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddb3b02246ddcffd3ce98e88fed5b238bc5faff10dbbaa42090ea13241d15764"}, + {file = "matplotlib-3.9.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8a75287e9cb9eee48cb79ec1d806f75b29c0fde978cb7223a1f4c5848d696041"}, + {file = "matplotlib-3.9.4-cp313-cp313t-win_amd64.whl", hash = "sha256:488deb7af140f0ba86da003e66e10d55ff915e152c78b4b66d231638400b1965"}, + {file = "matplotlib-3.9.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3c3724d89a387ddf78ff88d2a30ca78ac2b4c89cf37f2db4bd453c34799e933c"}, + {file = "matplotlib-3.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d5f0a8430ffe23d7e32cfd86445864ccad141797f7d25b7c41759a5b5d17cfd7"}, + {file = "matplotlib-3.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bb0141a21aef3b64b633dc4d16cbd5fc538b727e4958be82a0e1c92a234160e"}, + {file = "matplotlib-3.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57aa235109e9eed52e2c2949db17da185383fa71083c00c6c143a60e07e0888c"}, + {file = "matplotlib-3.9.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b18c600061477ccfdd1e6fd050c33d8be82431700f3452b297a56d9ed7037abb"}, + {file = "matplotlib-3.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:ef5f2d1b67d2d2145ff75e10f8c008bfbf71d45137c4b648c87193e7dd053eac"}, + {file = "matplotlib-3.9.4-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:44e0ed786d769d85bc787b0606a53f2d8d2d1d3c8a2608237365e9121c1a338c"}, + {file = "matplotlib-3.9.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:09debb9ce941eb23ecdbe7eab972b1c3e0276dcf01688073faff7b0f61d6c6ca"}, + {file = "matplotlib-3.9.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc53cf157a657bfd03afab14774d54ba73aa84d42cfe2480c91bd94873952db"}, + {file = "matplotlib-3.9.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ad45da51be7ad02387801fd154ef74d942f49fe3fcd26a64c94842ba7ec0d865"}, + {file = "matplotlib-3.9.4.tar.gz", hash = "sha256:1e00e8be7393cbdc6fedfa8a6fba02cf3e83814b285db1c60b906a023ba41bc3"}, +] + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} +kiwisolver = ">=1.3.1" +numpy = ">=1.23" +packaging = ">=20.0" +pillow = ">=8" +pyparsing = ">=2.3.1" +python-dateutil = ">=2.7" + +[package.extras] +dev = ["meson-python (>=0.13.1,<0.17.0)", "numpy (>=1.25)", "pybind11 (>=2.6,!=2.13.3)", "setuptools (>=64)", "setuptools_scm (>=7)"] + +[[package]] +name = "matplotlib" +version = "3.10.6" +description = "Python plotting package" +optional = false +python-versions = ">=3.10" +groups = ["main"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "matplotlib-3.10.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:bc7316c306d97463a9866b89d5cc217824e799fa0de346c8f68f4f3d27c8693d"}, + {file = "matplotlib-3.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d00932b0d160ef03f59f9c0e16d1e3ac89646f7785165ce6ad40c842db16cc2e"}, + {file = "matplotlib-3.10.6-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8fa4c43d6bfdbfec09c733bca8667de11bfa4970e8324c471f3a3632a0301c15"}, + {file = "matplotlib-3.10.6-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ea117a9c1627acaa04dbf36265691921b999cbf515a015298e54e1a12c3af837"}, + {file = "matplotlib-3.10.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08fc803293b4e1694ee325896030de97f74c141ccff0be886bb5915269247676"}, + {file = "matplotlib-3.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:2adf92d9b7527fbfb8818e050260f0ebaa460f79d61546374ce73506c9421d09"}, + {file = "matplotlib-3.10.6-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:905b60d1cb0ee604ce65b297b61cf8be9f4e6cfecf95a3fe1c388b5266bc8f4f"}, + {file = "matplotlib-3.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7bac38d816637343e53d7185d0c66677ff30ffb131044a81898b5792c956ba76"}, + {file = "matplotlib-3.10.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:942a8de2b5bfff1de31d95722f702e2966b8a7e31f4e68f7cd963c7cd8861cf6"}, + {file = "matplotlib-3.10.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3276c85370bc0dfca051ec65c5817d1e0f8f5ce1b7787528ec8ed2d524bbc2f"}, + {file = "matplotlib-3.10.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9df5851b219225731f564e4b9e7f2ac1e13c9e6481f941b5631a0f8e2d9387ce"}, + {file = "matplotlib-3.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:abb5d9478625dd9c9eb51a06d39aae71eda749ae9b3138afb23eb38824026c7e"}, + {file = "matplotlib-3.10.6-cp311-cp311-win_arm64.whl", hash = "sha256:886f989ccfae63659183173bb3fced7fd65e9eb793c3cc21c273add368536951"}, + {file = "matplotlib-3.10.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:31ca662df6a80bd426f871105fdd69db7543e28e73a9f2afe80de7e531eb2347"}, + {file = "matplotlib-3.10.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1678bb61d897bb4ac4757b5ecfb02bfb3fddf7f808000fb81e09c510712fda75"}, + {file = "matplotlib-3.10.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:56cd2d20842f58c03d2d6e6c1f1cf5548ad6f66b91e1e48f814e4fb5abd1cb95"}, + {file = "matplotlib-3.10.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:662df55604a2f9a45435566d6e2660e41efe83cd94f4288dfbf1e6d1eae4b0bb"}, + {file = "matplotlib-3.10.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:08f141d55148cd1fc870c3387d70ca4df16dee10e909b3b038782bd4bda6ea07"}, + {file = "matplotlib-3.10.6-cp312-cp312-win_amd64.whl", hash = "sha256:590f5925c2d650b5c9d813c5b3b5fc53f2929c3f8ef463e4ecfa7e052044fb2b"}, + {file = "matplotlib-3.10.6-cp312-cp312-win_arm64.whl", hash = "sha256:f44c8d264a71609c79a78d50349e724f5d5fc3684ead7c2a473665ee63d868aa"}, + {file = "matplotlib-3.10.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:819e409653c1106c8deaf62e6de6b8611449c2cd9939acb0d7d4e57a3d95cc7a"}, + {file = "matplotlib-3.10.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:59c8ac8382fefb9cb71308dde16a7c487432f5255d8f1fd32473523abecfecdf"}, + {file = "matplotlib-3.10.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:84e82d9e0fd70c70bc55739defbd8055c54300750cbacf4740c9673a24d6933a"}, + {file = "matplotlib-3.10.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25f7a3eb42d6c1c56e89eacd495661fc815ffc08d9da750bca766771c0fd9110"}, + {file = "matplotlib-3.10.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f9c862d91ec0b7842920a4cfdaaec29662195301914ea54c33e01f1a28d014b2"}, + {file = "matplotlib-3.10.6-cp313-cp313-win_amd64.whl", hash = "sha256:1b53bd6337eba483e2e7d29c5ab10eee644bc3a2491ec67cc55f7b44583ffb18"}, + {file = "matplotlib-3.10.6-cp313-cp313-win_arm64.whl", hash = "sha256:cbd5eb50b7058b2892ce45c2f4e92557f395c9991f5c886d1bb74a1582e70fd6"}, + {file = "matplotlib-3.10.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:acc86dd6e0e695c095001a7fccff158c49e45e0758fdf5dcdbb0103318b59c9f"}, + {file = "matplotlib-3.10.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e228cd2ffb8f88b7d0b29e37f68ca9aaf83e33821f24a5ccc4f082dd8396bc27"}, + {file = "matplotlib-3.10.6-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:658bc91894adeab669cf4bb4a186d049948262987e80f0857216387d7435d833"}, + {file = "matplotlib-3.10.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8913b7474f6dd83ac444c9459c91f7f0f2859e839f41d642691b104e0af056aa"}, + {file = "matplotlib-3.10.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:091cea22e059b89f6d7d1a18e2c33a7376c26eee60e401d92a4d6726c4e12706"}, + {file = "matplotlib-3.10.6-cp313-cp313t-win_amd64.whl", hash = "sha256:491e25e02a23d7207629d942c666924a6b61e007a48177fdd231a0097b7f507e"}, + {file = "matplotlib-3.10.6-cp313-cp313t-win_arm64.whl", hash = "sha256:3d80d60d4e54cda462e2cd9a086d85cd9f20943ead92f575ce86885a43a565d5"}, + {file = "matplotlib-3.10.6-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:70aaf890ce1d0efd482df969b28a5b30ea0b891224bb315810a3940f67182899"}, + {file = "matplotlib-3.10.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1565aae810ab79cb72e402b22facfa6501365e73ebab70a0fdfb98488d2c3c0c"}, + {file = "matplotlib-3.10.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3b23315a01981689aa4e1a179dbf6ef9fbd17143c3eea77548c2ecfb0499438"}, + {file = "matplotlib-3.10.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:30fdd37edf41a4e6785f9b37969de57aea770696cb637d9946eb37470c94a453"}, + {file = "matplotlib-3.10.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bc31e693da1c08012c764b053e702c1855378e04102238e6a5ee6a7117c53a47"}, + {file = "matplotlib-3.10.6-cp314-cp314-win_amd64.whl", hash = "sha256:05be9bdaa8b242bc6ff96330d18c52f1fc59c6fb3a4dd411d953d67e7e1baf98"}, + {file = "matplotlib-3.10.6-cp314-cp314-win_arm64.whl", hash = "sha256:f56a0d1ab05d34c628592435781d185cd99630bdfd76822cd686fb5a0aecd43a"}, + {file = "matplotlib-3.10.6-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:94f0b4cacb23763b64b5dace50d5b7bfe98710fed5f0cef5c08135a03399d98b"}, + {file = "matplotlib-3.10.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cc332891306b9fb39462673d8225d1b824c89783fee82840a709f96714f17a5c"}, + {file = "matplotlib-3.10.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee1d607b3fb1590deb04b69f02ea1d53ed0b0bf75b2b1a5745f269afcbd3cdd3"}, + {file = "matplotlib-3.10.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:376a624a218116461696b27b2bbf7a8945053e6d799f6502fc03226d077807bf"}, + {file = "matplotlib-3.10.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:83847b47f6524c34b4f2d3ce726bb0541c48c8e7692729865c3df75bfa0f495a"}, + {file = "matplotlib-3.10.6-cp314-cp314t-win_amd64.whl", hash = "sha256:c7e0518e0d223683532a07f4b512e2e0729b62674f1b3a1a69869f98e6b1c7e3"}, + {file = "matplotlib-3.10.6-cp314-cp314t-win_arm64.whl", hash = "sha256:4dd83e029f5b4801eeb87c64efd80e732452781c16a9cf7415b7b63ec8f374d7"}, + {file = "matplotlib-3.10.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:13fcd07ccf17e354398358e0307a1f53f5325dca22982556ddb9c52837b5af41"}, + {file = "matplotlib-3.10.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:470fc846d59d1406e34fa4c32ba371039cd12c2fe86801159a965956f2575bd1"}, + {file = "matplotlib-3.10.6-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f7173f8551b88f4ef810a94adae3128c2530e0d07529f7141be7f8d8c365f051"}, + {file = "matplotlib-3.10.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f2d684c3204fa62421bbf770ddfebc6b50130f9cad65531eeba19236d73bb488"}, + {file = "matplotlib-3.10.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:6f4a69196e663a41d12a728fab8751177215357906436804217d6d9cf0d4d6cf"}, + {file = "matplotlib-3.10.6-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d6ca6ef03dfd269f4ead566ec6f3fb9becf8dab146fb999022ed85ee9f6b3eb"}, + {file = "matplotlib-3.10.6.tar.gz", hash = "sha256:ec01b645840dd1996df21ee37f208cd8ba57644779fa20464010638013d3203c"}, +] + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +kiwisolver = ">=1.3.1" +numpy = ">=1.23" +packaging = ">=20.0" +pillow = ">=8" +pyparsing = ">=2.3.1" +python-dateutil = ">=2.7" + +[package.extras] +dev = ["meson-python (>=0.13.1,<0.17.0)", "pybind11 (>=2.13.2,!=2.13.3)", "setuptools (>=64)", "setuptools_scm (>=7)"] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mdit-py-plugins" +version = "0.4.2" +description = "Collection of plugins for markdown-it-py" +optional = false +python-versions = ">=3.8" +groups = ["docs"] +markers = "python_version < \"3.11\"" +files = [ + {file = "mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636"}, + {file = "mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5"}, +] + +[package.dependencies] +markdown-it-py = ">=1.0.0,<4.0.0" + +[package.extras] +code-style = ["pre-commit"] +rtd = ["myst-parser", "sphinx-book-theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mdit-py-plugins" +version = "0.5.0" +description = "Collection of plugins for markdown-it-py" +optional = false +python-versions = ">=3.10" +groups = ["docs"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "mdit_py_plugins-0.5.0-py3-none-any.whl", hash = "sha256:07a08422fc1936a5d26d146759e9155ea466e842f5ab2f7d2266dd084c8dab1f"}, + {file = "mdit_py_plugins-0.5.0.tar.gz", hash = "sha256:f4918cb50119f50446560513a8e311d574ff6aaed72606ddae6d35716fe809c6"}, +] + +[package.dependencies] +markdown-it-py = ">=2.0.0,<5.0.0" + +[package.extras] +code-style = ["pre-commit"] +rtd = ["myst-parser", "sphinx-book-theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +groups = ["dev", "docs"] +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "mock" +version = "5.2.0" +description = "Rolling backport of unittest.mock for all Pythons" +optional = false +python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "mock-5.2.0-py3-none-any.whl", hash = "sha256:7ba87f72ca0e915175596069dbbcc7c75af7b5e9b9bc107ad6349ede0819982f"}, + {file = "mock-5.2.0.tar.gz", hash = "sha256:4e460e818629b4b173f32d08bf30d3af8123afbb8e04bb5707a1fd4799e503f0"}, +] + +[package.extras] +build = ["blurb", "twine", "wheel"] +docs = ["sphinx"] +test = ["pytest", "pytest-cov"] + +[[package]] +name = "mpmath" +version = "1.3.0" +description = "Python library for arbitrary-precision floating-point arithmetic" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"}, + {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"}, +] + +[package.extras] +develop = ["codecov", "pycodestyle", "pytest (>=4.6)", "pytest-cov", "wheel"] +docs = ["sphinx"] +gmpy = ["gmpy2 (>=2.1.0a4) ; platform_python_implementation != \"PyPy\""] +tests = ["pytest (>=4.6)"] + +[[package]] +name = "multidict" +version = "6.6.4" +description = "multidict implementation" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "multidict-6.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b8aa6f0bd8125ddd04a6593437bad6a7e70f300ff4180a531654aa2ab3f6d58f"}, + {file = "multidict-6.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9e5853bbd7264baca42ffc53391b490d65fe62849bf2c690fa3f6273dbcd0cb"}, + {file = "multidict-6.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0af5f9dee472371e36d6ae38bde009bd8ce65ac7335f55dcc240379d7bed1495"}, + {file = "multidict-6.6.4-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:d24f351e4d759f5054b641c81e8291e5d122af0fca5c72454ff77f7cbe492de8"}, + {file = "multidict-6.6.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db6a3810eec08280a172a6cd541ff4a5f6a97b161d93ec94e6c4018917deb6b7"}, + {file = "multidict-6.6.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a1b20a9d56b2d81e2ff52ecc0670d583eaabaa55f402e8d16dd062373dbbe796"}, + {file = "multidict-6.6.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8c9854df0eaa610a23494c32a6f44a3a550fb398b6b51a56e8c6b9b3689578db"}, + {file = "multidict-6.6.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4bb7627fd7a968f41905a4d6343b0d63244a0623f006e9ed989fa2b78f4438a0"}, + {file = "multidict-6.6.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:caebafea30ed049c57c673d0b36238b1748683be2593965614d7b0e99125c877"}, + {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ad887a8250eb47d3ab083d2f98db7f48098d13d42eb7a3b67d8a5c795f224ace"}, + {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ed8358ae7d94ffb7c397cecb62cbac9578a83ecefc1eba27b9090ee910e2efb6"}, + {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ecab51ad2462197a4c000b6d5701fc8585b80eecb90583635d7e327b7b6923eb"}, + {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c5c97aa666cf70e667dfa5af945424ba1329af5dd988a437efeb3a09430389fb"}, + {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:9a950b7cf54099c1209f455ac5970b1ea81410f2af60ed9eb3c3f14f0bfcf987"}, + {file = "multidict-6.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:163c7ea522ea9365a8a57832dea7618e6cbdc3cd75f8c627663587459a4e328f"}, + {file = "multidict-6.6.4-cp310-cp310-win32.whl", hash = "sha256:17d2cbbfa6ff20821396b25890f155f40c986f9cfbce5667759696d83504954f"}, + {file = "multidict-6.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:ce9a40fbe52e57e7edf20113a4eaddfacac0561a0879734e636aa6d4bb5e3fb0"}, + {file = "multidict-6.6.4-cp310-cp310-win_arm64.whl", hash = "sha256:01d0959807a451fe9fdd4da3e139cb5b77f7328baf2140feeaf233e1d777b729"}, + {file = "multidict-6.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c7a0e9b561e6460484318a7612e725df1145d46b0ef57c6b9866441bf6e27e0c"}, + {file = "multidict-6.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6bf2f10f70acc7a2446965ffbc726e5fc0b272c97a90b485857e5c70022213eb"}, + {file = "multidict-6.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66247d72ed62d5dd29752ffc1d3b88f135c6a8de8b5f63b7c14e973ef5bda19e"}, + {file = "multidict-6.6.4-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:105245cc6b76f51e408451a844a54e6823bbd5a490ebfe5bdfc79798511ceded"}, + {file = "multidict-6.6.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cbbc54e58b34c3bae389ef00046be0961f30fef7cb0dd9c7756aee376a4f7683"}, + {file = "multidict-6.6.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:56c6b3652f945c9bc3ac6c8178cd93132b8d82dd581fcbc3a00676c51302bc1a"}, + {file = "multidict-6.6.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b95494daf857602eccf4c18ca33337dd2be705bccdb6dddbfc9d513e6addb9d9"}, + {file = "multidict-6.6.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e5b1413361cef15340ab9dc61523e653d25723e82d488ef7d60a12878227ed50"}, + {file = "multidict-6.6.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e167bf899c3d724f9662ef00b4f7fef87a19c22b2fead198a6f68b263618df52"}, + {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aaea28ba20a9026dfa77f4b80369e51cb767c61e33a2d4043399c67bd95fb7c6"}, + {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8c91cdb30809a96d9ecf442ec9bc45e8cfaa0f7f8bdf534e082c2443a196727e"}, + {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1a0ccbfe93ca114c5d65a2471d52d8829e56d467c97b0e341cf5ee45410033b3"}, + {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:55624b3f321d84c403cb7d8e6e982f41ae233d85f85db54ba6286f7295dc8a9c"}, + {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4a1fb393a2c9d202cb766c76208bd7945bc194eba8ac920ce98c6e458f0b524b"}, + {file = "multidict-6.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:43868297a5759a845fa3a483fb4392973a95fb1de891605a3728130c52b8f40f"}, + {file = "multidict-6.6.4-cp311-cp311-win32.whl", hash = "sha256:ed3b94c5e362a8a84d69642dbeac615452e8af9b8eb825b7bc9f31a53a1051e2"}, + {file = "multidict-6.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:d8c112f7a90d8ca5d20213aa41eac690bb50a76da153e3afb3886418e61cb22e"}, + {file = "multidict-6.6.4-cp311-cp311-win_arm64.whl", hash = "sha256:3bb0eae408fa1996d87247ca0d6a57b7fc1dcf83e8a5c47ab82c558c250d4adf"}, + {file = "multidict-6.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0ffb87be160942d56d7b87b0fdf098e81ed565add09eaa1294268c7f3caac4c8"}, + {file = "multidict-6.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d191de6cbab2aff5de6c5723101705fd044b3e4c7cfd587a1929b5028b9714b3"}, + {file = "multidict-6.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38a0956dd92d918ad5feff3db8fcb4a5eb7dba114da917e1a88475619781b57b"}, + {file = "multidict-6.6.4-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:6865f6d3b7900ae020b495d599fcf3765653bc927951c1abb959017f81ae8287"}, + {file = "multidict-6.6.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a2088c126b6f72db6c9212ad827d0ba088c01d951cee25e758c450da732c138"}, + {file = "multidict-6.6.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0f37bed7319b848097085d7d48116f545985db988e2256b2e6f00563a3416ee6"}, + {file = "multidict-6.6.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:01368e3c94032ba6ca0b78e7ccb099643466cf24f8dc8eefcfdc0571d56e58f9"}, + {file = "multidict-6.6.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fe323540c255db0bffee79ad7f048c909f2ab0edb87a597e1c17da6a54e493c"}, + {file = "multidict-6.6.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8eb3025f17b0a4c3cd08cda49acf312a19ad6e8a4edd9dbd591e6506d999402"}, + {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bbc14f0365534d35a06970d6a83478b249752e922d662dc24d489af1aa0d1be7"}, + {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:75aa52fba2d96bf972e85451b99d8e19cc37ce26fd016f6d4aa60da9ab2b005f"}, + {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4fefd4a815e362d4f011919d97d7b4a1e566f1dde83dc4ad8cfb5b41de1df68d"}, + {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:db9801fe021f59a5b375ab778973127ca0ac52429a26e2fd86aa9508f4d26eb7"}, + {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a650629970fa21ac1fb06ba25dabfc5b8a2054fcbf6ae97c758aa956b8dba802"}, + {file = "multidict-6.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:452ff5da78d4720d7516a3a2abd804957532dd69296cb77319c193e3ffb87e24"}, + {file = "multidict-6.6.4-cp312-cp312-win32.whl", hash = "sha256:8c2fcb12136530ed19572bbba61b407f655e3953ba669b96a35036a11a485793"}, + {file = "multidict-6.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:047d9425860a8c9544fed1b9584f0c8bcd31bcde9568b047c5e567a1025ecd6e"}, + {file = "multidict-6.6.4-cp312-cp312-win_arm64.whl", hash = "sha256:14754eb72feaa1e8ae528468f24250dd997b8e2188c3d2f593f9eba259e4b364"}, + {file = "multidict-6.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f46a6e8597f9bd71b31cc708195d42b634c8527fecbcf93febf1052cacc1f16e"}, + {file = "multidict-6.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:22e38b2bc176c5eb9c0a0e379f9d188ae4cd8b28c0f53b52bce7ab0a9e534657"}, + {file = "multidict-6.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5df8afd26f162da59e218ac0eefaa01b01b2e6cd606cffa46608f699539246da"}, + {file = "multidict-6.6.4-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:49517449b58d043023720aa58e62b2f74ce9b28f740a0b5d33971149553d72aa"}, + {file = "multidict-6.6.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9408439537c5afdca05edd128a63f56a62680f4b3c234301055d7a2000220f"}, + {file = "multidict-6.6.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87a32d20759dc52a9e850fe1061b6e41ab28e2998d44168a8a341b99ded1dba0"}, + {file = "multidict-6.6.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:52e3c8d43cdfff587ceedce9deb25e6ae77daba560b626e97a56ddcad3756879"}, + {file = "multidict-6.6.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ad8850921d3a8d8ff6fbef790e773cecfc260bbfa0566998980d3fa8f520bc4a"}, + {file = "multidict-6.6.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:497a2954adc25c08daff36f795077f63ad33e13f19bfff7736e72c785391534f"}, + {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:024ce601f92d780ca1617ad4be5ac15b501cc2414970ffa2bb2bbc2bd5a68fa5"}, + {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a693fc5ed9bdd1c9e898013e0da4dcc640de7963a371c0bd458e50e046bf6438"}, + {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:190766dac95aab54cae5b152a56520fd99298f32a1266d66d27fdd1b5ac00f4e"}, + {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:34d8f2a5ffdceab9dcd97c7a016deb2308531d5f0fced2bb0c9e1df45b3363d7"}, + {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:59e8d40ab1f5a8597abcef00d04845155a5693b5da00d2c93dbe88f2050f2812"}, + {file = "multidict-6.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:467fe64138cfac771f0e949b938c2e1ada2b5af22f39692aa9258715e9ea613a"}, + {file = "multidict-6.6.4-cp313-cp313-win32.whl", hash = "sha256:14616a30fe6d0a48d0a48d1a633ab3b8bec4cf293aac65f32ed116f620adfd69"}, + {file = "multidict-6.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:40cd05eaeb39e2bc8939451f033e57feaa2ac99e07dbca8afe2be450a4a3b6cf"}, + {file = "multidict-6.6.4-cp313-cp313-win_arm64.whl", hash = "sha256:f6eb37d511bfae9e13e82cb4d1af36b91150466f24d9b2b8a9785816deb16605"}, + {file = "multidict-6.6.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6c84378acd4f37d1b507dfa0d459b449e2321b3ba5f2338f9b085cf7a7ba95eb"}, + {file = "multidict-6.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0e0558693063c75f3d952abf645c78f3c5dfdd825a41d8c4d8156fc0b0da6e7e"}, + {file = "multidict-6.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3f8e2384cb83ebd23fd07e9eada8ba64afc4c759cd94817433ab8c81ee4b403f"}, + {file = "multidict-6.6.4-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f996b87b420995a9174b2a7c1a8daf7db4750be6848b03eb5e639674f7963773"}, + {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc356250cffd6e78416cf5b40dc6a74f1edf3be8e834cf8862d9ed5265cf9b0e"}, + {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:dadf95aa862714ea468a49ad1e09fe00fcc9ec67d122f6596a8d40caf6cec7d0"}, + {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7dd57515bebffd8ebd714d101d4c434063322e4fe24042e90ced41f18b6d3395"}, + {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:967af5f238ebc2eb1da4e77af5492219fbd9b4b812347da39a7b5f5c72c0fa45"}, + {file = "multidict-6.6.4-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a4c6875c37aae9794308ec43e3530e4aa0d36579ce38d89979bbf89582002bb"}, + {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7f683a551e92bdb7fac545b9c6f9fa2aebdeefa61d607510b3533286fcab67f5"}, + {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:3ba5aaf600edaf2a868a391779f7a85d93bed147854925f34edd24cc70a3e141"}, + {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:580b643b7fd2c295d83cad90d78419081f53fd532d1f1eb67ceb7060f61cff0d"}, + {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:37b7187197da6af3ee0b044dbc9625afd0c885f2800815b228a0e70f9a7f473d"}, + {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e1b93790ed0bc26feb72e2f08299691ceb6da5e9e14a0d13cc74f1869af327a0"}, + {file = "multidict-6.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a506a77ddee1efcca81ecbeae27ade3e09cdf21a8ae854d766c2bb4f14053f92"}, + {file = "multidict-6.6.4-cp313-cp313t-win32.whl", hash = "sha256:f93b2b2279883d1d0a9e1bd01f312d6fc315c5e4c1f09e112e4736e2f650bc4e"}, + {file = "multidict-6.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:6d46a180acdf6e87cc41dc15d8f5c2986e1e8739dc25dbb7dac826731ef381a4"}, + {file = "multidict-6.6.4-cp313-cp313t-win_arm64.whl", hash = "sha256:756989334015e3335d087a27331659820d53ba432befdef6a718398b0a8493ad"}, + {file = "multidict-6.6.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:af7618b591bae552b40dbb6f93f5518328a949dac626ee75927bba1ecdeea9f4"}, + {file = "multidict-6.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b6819f83aef06f560cb15482d619d0e623ce9bf155115150a85ab11b8342a665"}, + {file = "multidict-6.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4d09384e75788861e046330308e7af54dd306aaf20eb760eb1d0de26b2bea2cb"}, + {file = "multidict-6.6.4-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:a59c63061f1a07b861c004e53869eb1211ffd1a4acbca330e3322efa6dd02978"}, + {file = "multidict-6.6.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:350f6b0fe1ced61e778037fdc7613f4051c8baf64b1ee19371b42a3acdb016a0"}, + {file = "multidict-6.6.4-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0c5cbac6b55ad69cb6aa17ee9343dfbba903118fd530348c330211dc7aa756d1"}, + {file = "multidict-6.6.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:630f70c32b8066ddfd920350bc236225814ad94dfa493fe1910ee17fe4365cbb"}, + {file = "multidict-6.6.4-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f8d4916a81697faec6cb724a273bd5457e4c6c43d82b29f9dc02c5542fd21fc9"}, + {file = "multidict-6.6.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e42332cf8276bb7645d310cdecca93a16920256a5b01bebf747365f86a1675b"}, + {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f3be27440f7644ab9a13a6fc86f09cdd90b347c3c5e30c6d6d860de822d7cb53"}, + {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:21f216669109e02ef3e2415ede07f4f8987f00de8cdfa0cc0b3440d42534f9f0"}, + {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:d9890d68c45d1aeac5178ded1d1cccf3bc8d7accf1f976f79bf63099fb16e4bd"}, + {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:edfdcae97cdc5d1a89477c436b61f472c4d40971774ac4729c613b4b133163cb"}, + {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:0b2e886624be5773e69cf32bcb8534aecdeb38943520b240fed3d5596a430f2f"}, + {file = "multidict-6.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:be5bf4b3224948032a845d12ab0f69f208293742df96dc14c4ff9b09e508fc17"}, + {file = "multidict-6.6.4-cp39-cp39-win32.whl", hash = "sha256:10a68a9191f284fe9d501fef4efe93226e74df92ce7a24e301371293bd4918ae"}, + {file = "multidict-6.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:ee25f82f53262f9ac93bd7e58e47ea1bdcc3393cef815847e397cba17e284210"}, + {file = "multidict-6.6.4-cp39-cp39-win_arm64.whl", hash = "sha256:f9867e55590e0855bcec60d4f9a092b69476db64573c9fe17e92b0c50614c16a"}, + {file = "multidict-6.6.4-py3-none-any.whl", hash = "sha256:27d8f8e125c07cb954e54d75d04905a9bba8a439c1d84aca94949d4d03d8601c"}, + {file = "multidict-6.6.4.tar.gz", hash = "sha256:d2d4e4787672911b48350df02ed3fa3fffdc2f2e8ca06dd6afdf34189b76a9dd"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} + +[[package]] +name = "multiprocess" +version = "0.70.16" +description = "better multiprocessing and multithreading in Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "multiprocess-0.70.16-pp310-pypy310_pp73-macosx_10_13_x86_64.whl", hash = "sha256:476887be10e2f59ff183c006af746cb6f1fd0eadcfd4ef49e605cbe2659920ee"}, + {file = "multiprocess-0.70.16-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d951bed82c8f73929ac82c61f01a7b5ce8f3e5ef40f5b52553b4f547ce2b08ec"}, + {file = "multiprocess-0.70.16-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:37b55f71c07e2d741374998c043b9520b626a8dddc8b3129222ca4f1a06ef67a"}, + {file = "multiprocess-0.70.16-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ba8c31889abf4511c7308a8c52bb4a30b9d590e7f58523302ba00237702ca054"}, + {file = "multiprocess-0.70.16-pp39-pypy39_pp73-macosx_10_13_x86_64.whl", hash = "sha256:0dfd078c306e08d46d7a8d06fb120313d87aa43af60d66da43ffff40b44d2f41"}, + {file = "multiprocess-0.70.16-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e7b9d0f307cd9bd50851afaac0dba2cb6c44449efff697df7c7645f7d3f2be3a"}, + {file = "multiprocess-0.70.16-py310-none-any.whl", hash = "sha256:c4a9944c67bd49f823687463660a2d6daae94c289adff97e0f9d696ba6371d02"}, + {file = "multiprocess-0.70.16-py311-none-any.whl", hash = "sha256:af4cabb0dac72abfb1e794fa7855c325fd2b55a10a44628a3c1ad3311c04127a"}, + {file = "multiprocess-0.70.16-py312-none-any.whl", hash = "sha256:fc0544c531920dde3b00c29863377f87e1632601092ea2daca74e4beb40faa2e"}, + {file = "multiprocess-0.70.16-py38-none-any.whl", hash = "sha256:a71d82033454891091a226dfc319d0cfa8019a4e888ef9ca910372a446de4435"}, + {file = "multiprocess-0.70.16-py39-none-any.whl", hash = "sha256:a0bafd3ae1b732eac64be2e72038231c1ba97724b60b09400d68f229fcc2fbf3"}, + {file = "multiprocess-0.70.16.tar.gz", hash = "sha256:161af703d4652a0e1410be6abccecde4a7ddffd19341be0a7011b94aeb171ac1"}, +] + +[package.dependencies] +dill = ">=0.3.8" + +[[package]] +name = "mypy" +version = "1.4.0" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "mypy-1.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3af348e0925a59213244f28c7c0c3a2c2088b4ba2fe9d6c8d4fbb0aba0b7d05"}, + {file = "mypy-1.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0b2e0da7ff9dd8d2066d093d35a169305fc4e38db378281fce096768a3dbdbf"}, + {file = "mypy-1.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210fe0f39ec5be45dd9d0de253cb79245f0a6f27631d62e0c9c7988be7152965"}, + {file = "mypy-1.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f7a5971490fd4a5a436e143105a1f78fa8b3fe95b30fff2a77542b4f3227a01f"}, + {file = "mypy-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:50f65f0e9985f1e50040e603baebab83efed9eb37e15a22a4246fa7cd660f981"}, + {file = "mypy-1.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b1b5c875fcf3e7217a3de7f708166f641ca154b589664c44a6fd6d9f17d9e7e"}, + {file = "mypy-1.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b4c734d947e761c7ceb1f09a98359dd5666460acbc39f7d0a6b6beec373c5840"}, + {file = "mypy-1.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5984a8d13d35624e3b235a793c814433d810acba9eeefe665cdfed3d08bc3af"}, + {file = "mypy-1.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0f98973e39e4a98709546a9afd82e1ffcc50c6ec9ce6f7870f33ebbf0bd4f26d"}, + {file = "mypy-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:19d42b08c7532d736a7e0fb29525855e355fa51fd6aef4f9bbc80749ff64b1a2"}, + {file = "mypy-1.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6ba9a69172abaa73910643744d3848877d6aac4a20c41742027dcfd8d78f05d9"}, + {file = "mypy-1.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a34eed094c16cad0f6b0d889811592c7a9b7acf10d10a7356349e325d8704b4f"}, + {file = "mypy-1.4.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:53c2a1fed81e05ded10a4557fe12bae05b9ecf9153f162c662a71d924d504135"}, + {file = "mypy-1.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:bba57b4d2328740749f676807fcf3036e9de723530781405cc5a5e41fc6e20de"}, + {file = "mypy-1.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:653863c75f0dbb687d92eb0d4bd9fe7047d096987ecac93bb7b1bc336de48ebd"}, + {file = "mypy-1.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7461469e163f87a087a5e7aa224102a30f037c11a096a0ceeb721cb0dce274c8"}, + {file = "mypy-1.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cf0ca95e4b8adeaf07815a78b4096b65adf64ea7871b39a2116c19497fcd0dd"}, + {file = "mypy-1.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:94a81b9354545123feb1a99b960faeff9e1fa204fce47e0042335b473d71530d"}, + {file = "mypy-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:67242d5b28ed0fa88edd8f880aed24da481929467fdbca6487167cb5e3fd31ff"}, + {file = "mypy-1.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3f2b353eebef669529d9bd5ae3566905a685ae98b3af3aad7476d0d519714758"}, + {file = "mypy-1.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:62bf18d97c6b089f77f0067b4e321db089d8520cdeefc6ae3ec0f873621c22e5"}, + {file = "mypy-1.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca33ab70a4aaa75bb01086a0b04f0ba8441e51e06fc57e28585176b08cad533b"}, + {file = "mypy-1.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5a0ee54c2cb0f957f8a6f41794d68f1a7e32b9968675ade5846f538504856d42"}, + {file = "mypy-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:6c34d43e3d54ad05024576aef28081d9d0580f6fa7f131255f54020eb12f5352"}, + {file = "mypy-1.4.0-py3-none-any.whl", hash = "sha256:f051ca656be0c179c735a4c3193f307d34c92fdc4908d44fd4516fbe8b10567d"}, + {file = "mypy-1.4.0.tar.gz", hash = "sha256:de1e7e68148a213036276d1f5303b3836ad9a774188961eb2684eddff593b042"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=3.10" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +python2 = ["typed-ast (>=1.4.0,<2)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, +] + +[[package]] +name = "myst-parser" +version = "3.0.1" +description = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser," +optional = false +python-versions = ">=3.8" +groups = ["docs"] +markers = "python_version < \"3.11\"" +files = [ + {file = "myst_parser-3.0.1-py3-none-any.whl", hash = "sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1"}, + {file = "myst_parser-3.0.1.tar.gz", hash = "sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87"}, +] + +[package.dependencies] +docutils = ">=0.18,<0.22" +jinja2 = "*" +markdown-it-py = ">=3.0,<4.0" +mdit-py-plugins = ">=0.4,<1.0" +pyyaml = "*" +sphinx = ">=6,<8" + +[package.extras] +code-style = ["pre-commit (>=3.0,<4.0)"] +linkify = ["linkify-it-py (>=2.0,<3.0)"] +rtd = ["ipython", "sphinx (>=7)", "sphinx-autodoc2 (>=0.5.0,<0.6.0)", "sphinx-book-theme (>=1.1,<2.0)", "sphinx-copybutton", "sphinx-design", "sphinx-pyscript", "sphinx-tippy (>=0.4.3)", "sphinx-togglebutton", "sphinxext-opengraph (>=0.9.0,<0.10.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"] +testing = ["beautifulsoup4", "coverage[toml]", "defusedxml", "pytest (>=8,<9)", "pytest-cov", "pytest-param-files (>=0.6.0,<0.7.0)", "pytest-regressions", "sphinx-pytest"] +testing-docutils = ["pygments", "pytest (>=8,<9)", "pytest-param-files (>=0.6.0,<0.7.0)"] + +[[package]] +name = "myst-parser" +version = "4.0.1" +description = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser," +optional = false +python-versions = ">=3.10" +groups = ["docs"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "myst_parser-4.0.1-py3-none-any.whl", hash = "sha256:9134e88959ec3b5780aedf8a99680ea242869d012e8821db3126d427edc9c95d"}, + {file = "myst_parser-4.0.1.tar.gz", hash = "sha256:5cfea715e4f3574138aecbf7d54132296bfd72bb614d31168f48c477a830a7c4"}, +] + +[package.dependencies] +docutils = ">=0.19,<0.22" +jinja2 = "*" +markdown-it-py = ">=3.0,<4.0" +mdit-py-plugins = ">=0.4.1,<1.0" +pyyaml = "*" +sphinx = ">=7,<9" + +[package.extras] +code-style = ["pre-commit (>=4.0,<5.0)"] +linkify = ["linkify-it-py (>=2.0,<3.0)"] +rtd = ["ipython", "sphinx (>=7)", "sphinx-autodoc2 (>=0.5.0,<0.6.0)", "sphinx-book-theme (>=1.1,<2.0)", "sphinx-copybutton", "sphinx-design", "sphinx-pyscript", "sphinx-tippy (>=0.4.3)", "sphinx-togglebutton", "sphinxext-opengraph (>=0.9.0,<0.10.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"] +testing = ["beautifulsoup4", "coverage[toml]", "defusedxml", "pygments (<2.19)", "pytest (>=8,<9)", "pytest-cov", "pytest-param-files (>=0.6.0,<0.7.0)", "pytest-regressions", "sphinx-pytest"] +testing-docutils = ["pygments", "pytest (>=8,<9)", "pytest-param-files (>=0.6.0,<0.7.0)"] + +[[package]] +name = "narwhals" +version = "2.3.0" +description = "Extremely lightweight compatibility layer between dataframe libraries" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "narwhals-2.3.0-py3-none-any.whl", hash = "sha256:5507b1a9a9c2b1c55a627fdf6cf722fef2e23498bd14362a332c8848a311c321"}, + {file = "narwhals-2.3.0.tar.gz", hash = "sha256:b66bc4ab7b6746354f60c4b3941e3ce60c066588c35360e2dc6c063489000a16"}, +] + +[package.extras] +cudf = ["cudf (>=24.10.0)"] +dask = ["dask[dataframe] (>=2024.8)"] +duckdb = ["duckdb (>=1.0)"] +ibis = ["ibis-framework (>=6.0.0)", "packaging", "pyarrow-hotfix", "rich"] +modin = ["modin"] +pandas = ["pandas (>=1.1.3)"] +polars = ["polars (>=0.20.4)"] +pyarrow = ["pyarrow (>=13.0.0)"] +pyspark = ["pyspark (>=3.5.0)"] +pyspark-connect = ["pyspark[connect] (>=3.5.0)"] +sqlframe = ["sqlframe (>=3.22.0,!=3.39.3)"] + +[[package]] +name = "networkx" +version = "3.2.1" +description = "Python package for creating and manipulating graphs and networks" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version < \"3.11\"" +files = [ + {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, + {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, +] + +[package.extras] +default = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"] +developer = ["changelist (==0.4)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] +doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"] +extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"] +test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] + +[[package]] +name = "networkx" +version = "3.5" +description = "Python package for creating and manipulating graphs and networks" +optional = false +python-versions = ">=3.11" +groups = ["main"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec"}, + {file = "networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037"}, +] + +[package.extras] +default = ["matplotlib (>=3.8)", "numpy (>=1.25)", "pandas (>=2.0)", "scipy (>=1.11.2)"] +developer = ["mypy (>=1.15)", "pre-commit (>=4.1)"] +doc = ["intersphinx-registry", "myst-nb (>=1.1)", "numpydoc (>=1.8.0)", "pillow (>=10)", "pydata-sphinx-theme (>=0.16)", "sphinx (>=8.0)", "sphinx-gallery (>=0.18)", "texext (>=0.6.7)"] +example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "igraph (>=0.11)", "momepy (>=0.7.2)", "osmnx (>=2.0.0)", "scikit-learn (>=1.5)", "seaborn (>=0.13)"] +extra = ["lxml (>=4.6)", "pydot (>=3.0.1)", "pygraphviz (>=1.14)", "sympy (>=1.10)"] +test = ["pytest (>=7.2)", "pytest-cov (>=4.0)", "pytest-xdist (>=3.0)"] +test-extras = ["pytest-mpl", "pytest-randomly"] + +[[package]] +name = "nltk" +version = "3.9.1" +description = "Natural Language Toolkit" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "nltk-3.9.1-py3-none-any.whl", hash = "sha256:4fa26829c5b00715afe3061398a8989dc643b92ce7dd93fb4585a70930d168a1"}, + {file = "nltk-3.9.1.tar.gz", hash = "sha256:87d127bd3de4bd89a4f81265e5fa59cb1b199b27440175370f7417d2bc7ae868"}, +] + +[package.dependencies] +click = "*" +joblib = "*" +regex = ">=2021.8.3" +tqdm = "*" + +[package.extras] +all = ["matplotlib", "numpy", "pyparsing", "python-crfsuite", "requests", "scikit-learn", "scipy", "twython"] +corenlp = ["requests"] +machine-learning = ["numpy", "python-crfsuite", "scikit-learn", "scipy"] +plot = ["matplotlib"] +tgrep = ["pyparsing"] +twitter = ["twython"] + +[[package]] +name = "nodeenv" +version = "1.9.1" +description = "Node.js virtual environment builder" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] +files = [ + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, +] + +[[package]] +name = "numpy" +version = "2.0.2" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version < \"3.11\"" +files = [ + {file = "numpy-2.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:51129a29dbe56f9ca83438b706e2e69a39892b5eda6cedcb6b0c9fdc9b0d3ece"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f15975dfec0cf2239224d80e32c3170b1d168335eaedee69da84fbe9f1f9cd04"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:8c5713284ce4e282544c68d1c3b2c7161d38c256d2eefc93c1d683cf47683e66"}, + {file = "numpy-2.0.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:becfae3ddd30736fe1889a37f1f580e245ba79a5855bff5f2a29cb3ccc22dd7b"}, + {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2da5960c3cf0df7eafefd806d4e612c5e19358de82cb3c343631188991566ccd"}, + {file = "numpy-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:496f71341824ed9f3d2fd36cf3ac57ae2e0165c143b55c3a035ee219413f3318"}, + {file = "numpy-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a61ec659f68ae254e4d237816e33171497e978140353c0c2038d46e63282d0c8"}, + {file = "numpy-2.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d731a1c6116ba289c1e9ee714b08a8ff882944d4ad631fd411106a30f083c326"}, + {file = "numpy-2.0.2-cp310-cp310-win32.whl", hash = "sha256:984d96121c9f9616cd33fbd0618b7f08e0cfc9600a7ee1d6fd9b239186d19d97"}, + {file = "numpy-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:c7b0be4ef08607dd04da4092faee0b86607f111d5ae68036f16cc787e250a131"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:49ca4decb342d66018b01932139c0961a8f9ddc7589611158cb3c27cbcf76448"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:11a76c372d1d37437857280aa142086476136a8c0f373b2e648ab2c8f18fb195"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:807ec44583fd708a21d4a11d94aedf2f4f3c3719035c76a2bbe1fe8e217bdc57"}, + {file = "numpy-2.0.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8cafab480740e22f8d833acefed5cc87ce276f4ece12fdaa2e8903db2f82897a"}, + {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a15f476a45e6e5a3a79d8a14e62161d27ad897381fecfa4a09ed5322f2085669"}, + {file = "numpy-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13e689d772146140a252c3a28501da66dfecd77490b498b168b501835041f951"}, + {file = "numpy-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ea91dfb7c3d1c56a0e55657c0afb38cf1eeae4544c208dc465c3c9f3a7c09f9"}, + {file = "numpy-2.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c1c9307701fec8f3f7a1e6711f9089c06e6284b3afbbcd259f7791282d660a15"}, + {file = "numpy-2.0.2-cp311-cp311-win32.whl", hash = "sha256:a392a68bd329eafac5817e5aefeb39038c48b671afd242710b451e76090e81f4"}, + {file = "numpy-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:286cd40ce2b7d652a6f22efdfc6d1edf879440e53e76a75955bc0c826c7e64dc"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c"}, + {file = "numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c"}, + {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692"}, + {file = "numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a"}, + {file = "numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c"}, + {file = "numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded"}, + {file = "numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5"}, + {file = "numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9059e10581ce4093f735ed23f3b9d283b9d517ff46009ddd485f1747eb22653c"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:423e89b23490805d2a5a96fe40ec507407b8ee786d66f7328be214f9679df6dd"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_arm64.whl", hash = "sha256:2b2955fa6f11907cf7a70dab0d0755159bca87755e831e47932367fc8f2f2d0b"}, + {file = "numpy-2.0.2-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:97032a27bd9d8988b9a97a8c4d2c9f2c15a81f61e2f21404d7e8ef00cb5be729"}, + {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e795a8be3ddbac43274f18588329c72939870a16cae810c2b73461c40718ab1"}, + {file = "numpy-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b258c385842546006213344c50655ff1555a9338e2e5e02a0756dc3e803dd"}, + {file = "numpy-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fec9451a7789926bcf7c2b8d187292c9f93ea30284802a0ab3f5be8ab36865d"}, + {file = "numpy-2.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9189427407d88ff25ecf8f12469d4d39d35bee1db5d39fc5c168c6f088a6956d"}, + {file = "numpy-2.0.2-cp39-cp39-win32.whl", hash = "sha256:905d16e0c60200656500c95b6b8dca5d109e23cb24abc701d41c02d74c6b3afa"}, + {file = "numpy-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:a3f4ab0caa7f053f6797fcd4e1e25caee367db3112ef2b6ef82d749530768c73"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7f0a0c6f12e07fa94133c8a67404322845220c06a9e80e85999afe727f7438b8"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-macosx_14_0_x86_64.whl", hash = "sha256:312950fdd060354350ed123c0e25a71327d3711584beaef30cdaa93320c392d4"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26df23238872200f63518dd2aa984cfca675d82469535dc7162dc2ee52d9dd5c"}, + {file = "numpy-2.0.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a46288ec55ebbd58947d31d72be2c63cbf839f0a63b49cb755022310792a3385"}, + {file = "numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78"}, +] + +[[package]] +name = "numpy" +version = "2.3.2" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.11" +groups = ["main"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "numpy-2.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:852ae5bed3478b92f093e30f785c98e0cb62fa0a939ed057c31716e18a7a22b9"}, + {file = "numpy-2.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a0e27186e781a69959d0230dd9909b5e26024f8da10683bd6344baea1885168"}, + {file = "numpy-2.3.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:f0a1a8476ad77a228e41619af2fa9505cf69df928e9aaa165746584ea17fed2b"}, + {file = "numpy-2.3.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cbc95b3813920145032412f7e33d12080f11dc776262df1712e1638207dde9e8"}, + {file = "numpy-2.3.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f75018be4980a7324edc5930fe39aa391d5734531b1926968605416ff58c332d"}, + {file = "numpy-2.3.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20b8200721840f5621b7bd03f8dcd78de33ec522fc40dc2641aa09537df010c3"}, + {file = "numpy-2.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f91e5c028504660d606340a084db4b216567ded1056ea2b4be4f9d10b67197f"}, + {file = "numpy-2.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fb1752a3bb9a3ad2d6b090b88a9a0ae1cd6f004ef95f75825e2f382c183b2097"}, + {file = "numpy-2.3.2-cp311-cp311-win32.whl", hash = "sha256:4ae6863868aaee2f57503c7a5052b3a2807cf7a3914475e637a0ecd366ced220"}, + {file = "numpy-2.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:240259d6564f1c65424bcd10f435145a7644a65a6811cfc3201c4a429ba79170"}, + {file = "numpy-2.3.2-cp311-cp311-win_arm64.whl", hash = "sha256:4209f874d45f921bde2cff1ffcd8a3695f545ad2ffbef6d3d3c6768162efab89"}, + {file = "numpy-2.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bc3186bea41fae9d8e90c2b4fb5f0a1f5a690682da79b92574d63f56b529080b"}, + {file = "numpy-2.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f4f0215edb189048a3c03bd5b19345bdfa7b45a7a6f72ae5945d2a28272727f"}, + {file = "numpy-2.3.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8b1224a734cd509f70816455c3cffe13a4f599b1bf7130f913ba0e2c0b2006c0"}, + {file = "numpy-2.3.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3dcf02866b977a38ba3ec10215220609ab9667378a9e2150615673f3ffd6c73b"}, + {file = "numpy-2.3.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:572d5512df5470f50ada8d1972c5f1082d9a0b7aa5944db8084077570cf98370"}, + {file = "numpy-2.3.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8145dd6d10df13c559d1e4314df29695613575183fa2e2d11fac4c208c8a1f73"}, + {file = "numpy-2.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:103ea7063fa624af04a791c39f97070bf93b96d7af7eb23530cd087dc8dbe9dc"}, + {file = "numpy-2.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc927d7f289d14f5e037be917539620603294454130b6de200091e23d27dc9be"}, + {file = "numpy-2.3.2-cp312-cp312-win32.whl", hash = "sha256:d95f59afe7f808c103be692175008bab926b59309ade3e6d25009e9a171f7036"}, + {file = "numpy-2.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:9e196ade2400c0c737d93465327d1ae7c06c7cb8a1756121ebf54b06ca183c7f"}, + {file = "numpy-2.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:ee807923782faaf60d0d7331f5e86da7d5e3079e28b291973c545476c2b00d07"}, + {file = "numpy-2.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c8d9727f5316a256425892b043736d63e89ed15bbfe6556c5ff4d9d4448ff3b3"}, + {file = "numpy-2.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:efc81393f25f14d11c9d161e46e6ee348637c0a1e8a54bf9dedc472a3fae993b"}, + {file = "numpy-2.3.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:dd937f088a2df683cbb79dda9a772b62a3e5a8a7e76690612c2737f38c6ef1b6"}, + {file = "numpy-2.3.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:11e58218c0c46c80509186e460d79fbdc9ca1eb8d8aee39d8f2dc768eb781089"}, + {file = "numpy-2.3.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5ad4ebcb683a1f99f4f392cc522ee20a18b2bb12a2c1c42c3d48d5a1adc9d3d2"}, + {file = "numpy-2.3.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:938065908d1d869c7d75d8ec45f735a034771c6ea07088867f713d1cd3bbbe4f"}, + {file = "numpy-2.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:66459dccc65d8ec98cc7df61307b64bf9e08101f9598755d42d8ae65d9a7a6ee"}, + {file = "numpy-2.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a7af9ed2aa9ec5950daf05bb11abc4076a108bd3c7db9aa7251d5f107079b6a6"}, + {file = "numpy-2.3.2-cp313-cp313-win32.whl", hash = "sha256:906a30249315f9c8e17b085cc5f87d3f369b35fedd0051d4a84686967bdbbd0b"}, + {file = "numpy-2.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:c63d95dc9d67b676e9108fe0d2182987ccb0f11933c1e8959f42fa0da8d4fa56"}, + {file = "numpy-2.3.2-cp313-cp313-win_arm64.whl", hash = "sha256:b05a89f2fb84d21235f93de47129dd4f11c16f64c87c33f5e284e6a3a54e43f2"}, + {file = "numpy-2.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4e6ecfeddfa83b02318f4d84acf15fbdbf9ded18e46989a15a8b6995dfbf85ab"}, + {file = "numpy-2.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:508b0eada3eded10a3b55725b40806a4b855961040180028f52580c4729916a2"}, + {file = "numpy-2.3.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:754d6755d9a7588bdc6ac47dc4ee97867271b17cee39cb87aef079574366db0a"}, + {file = "numpy-2.3.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:a9f66e7d2b2d7712410d3bc5684149040ef5f19856f20277cd17ea83e5006286"}, + {file = "numpy-2.3.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:de6ea4e5a65d5a90c7d286ddff2b87f3f4ad61faa3db8dabe936b34c2275b6f8"}, + {file = "numpy-2.3.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3ef07ec8cbc8fc9e369c8dcd52019510c12da4de81367d8b20bc692aa07573a"}, + {file = "numpy-2.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:27c9f90e7481275c7800dc9c24b7cc40ace3fdb970ae4d21eaff983a32f70c91"}, + {file = "numpy-2.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:07b62978075b67eee4065b166d000d457c82a1efe726cce608b9db9dd66a73a5"}, + {file = "numpy-2.3.2-cp313-cp313t-win32.whl", hash = "sha256:c771cfac34a4f2c0de8e8c97312d07d64fd8f8ed45bc9f5726a7e947270152b5"}, + {file = "numpy-2.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:72dbebb2dcc8305c431b2836bcc66af967df91be793d63a24e3d9b741374c450"}, + {file = "numpy-2.3.2-cp313-cp313t-win_arm64.whl", hash = "sha256:72c6df2267e926a6d5286b0a6d556ebe49eae261062059317837fda12ddf0c1a"}, + {file = "numpy-2.3.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:448a66d052d0cf14ce9865d159bfc403282c9bc7bb2a31b03cc18b651eca8b1a"}, + {file = "numpy-2.3.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:546aaf78e81b4081b2eba1d105c3b34064783027a06b3ab20b6eba21fb64132b"}, + {file = "numpy-2.3.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:87c930d52f45df092f7578889711a0768094debf73cfcde105e2d66954358125"}, + {file = "numpy-2.3.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:8dc082ea901a62edb8f59713c6a7e28a85daddcb67454c839de57656478f5b19"}, + {file = "numpy-2.3.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:af58de8745f7fa9ca1c0c7c943616c6fe28e75d0c81f5c295810e3c83b5be92f"}, + {file = "numpy-2.3.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed5527c4cf10f16c6d0b6bee1f89958bccb0ad2522c8cadc2efd318bcd545f5"}, + {file = "numpy-2.3.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:095737ed986e00393ec18ec0b21b47c22889ae4b0cd2d5e88342e08b01141f58"}, + {file = "numpy-2.3.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b5e40e80299607f597e1a8a247ff8d71d79c5b52baa11cc1cce30aa92d2da6e0"}, + {file = "numpy-2.3.2-cp314-cp314-win32.whl", hash = "sha256:7d6e390423cc1f76e1b8108c9b6889d20a7a1f59d9a60cac4a050fa734d6c1e2"}, + {file = "numpy-2.3.2-cp314-cp314-win_amd64.whl", hash = "sha256:b9d0878b21e3918d76d2209c924ebb272340da1fb51abc00f986c258cd5e957b"}, + {file = "numpy-2.3.2-cp314-cp314-win_arm64.whl", hash = "sha256:2738534837c6a1d0c39340a190177d7d66fdf432894f469728da901f8f6dc910"}, + {file = "numpy-2.3.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:4d002ecf7c9b53240be3bb69d80f86ddbd34078bae04d87be81c1f58466f264e"}, + {file = "numpy-2.3.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:293b2192c6bcce487dbc6326de5853787f870aeb6c43f8f9c6496db5b1781e45"}, + {file = "numpy-2.3.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:0a4f2021a6da53a0d580d6ef5db29947025ae8b35b3250141805ea9a32bbe86b"}, + {file = "numpy-2.3.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:9c144440db4bf3bb6372d2c3e49834cc0ff7bb4c24975ab33e01199e645416f2"}, + {file = "numpy-2.3.2-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f92d6c2a8535dc4fe4419562294ff957f83a16ebdec66df0805e473ffaad8bd0"}, + {file = "numpy-2.3.2-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cefc2219baa48e468e3db7e706305fcd0c095534a192a08f31e98d83a7d45fb0"}, + {file = "numpy-2.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:76c3e9501ceb50b2ff3824c3589d5d1ab4ac857b0ee3f8f49629d0de55ecf7c2"}, + {file = "numpy-2.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:122bf5ed9a0221b3419672493878ba4967121514b1d7d4656a7580cd11dddcbf"}, + {file = "numpy-2.3.2-cp314-cp314t-win32.whl", hash = "sha256:6f1ae3dcb840edccc45af496f312528c15b1f79ac318169d094e85e4bb35fdf1"}, + {file = "numpy-2.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:087ffc25890d89a43536f75c5fe8770922008758e8eeeef61733957041ed2f9b"}, + {file = "numpy-2.3.2-cp314-cp314t-win_arm64.whl", hash = "sha256:092aeb3449833ea9c0bf0089d70c29ae480685dd2377ec9cdbbb620257f84631"}, + {file = "numpy-2.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:14a91ebac98813a49bc6aa1a0dfc09513dcec1d97eaf31ca21a87221a1cdcb15"}, + {file = "numpy-2.3.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:71669b5daae692189540cffc4c439468d35a3f84f0c88b078ecd94337f6cb0ec"}, + {file = "numpy-2.3.2-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:69779198d9caee6e547adb933941ed7520f896fd9656834c300bdf4dd8642712"}, + {file = "numpy-2.3.2-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:2c3271cc4097beb5a60f010bcc1cc204b300bb3eafb4399376418a83a1c6373c"}, + {file = "numpy-2.3.2-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8446acd11fe3dc1830568c941d44449fd5cb83068e5c70bd5a470d323d448296"}, + {file = "numpy-2.3.2-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa098a5ab53fa407fded5870865c6275a5cd4101cfdef8d6fafc48286a96e981"}, + {file = "numpy-2.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6936aff90dda378c09bea075af0d9c675fe3a977a9d2402f95a87f440f59f619"}, + {file = "numpy-2.3.2.tar.gz", hash = "sha256:e0486a11ec30cdecb53f184d496d1c6a20786c81e55e41640270130056f8ee48"}, +] + +[[package]] +name = "nvidia-cublas-cu12" +version = "12.6.4.1" +description = "CUBLAS native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_cublas_cu12-12.6.4.1-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:08ed2686e9875d01b58e3cb379c6896df8e76c75e0d4a7f7dace3d7b6d9ef8eb"}, + {file = "nvidia_cublas_cu12-12.6.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:235f728d6e2a409eddf1df58d5b0921cf80cfa9e72b9f2775ccb7b4a87984668"}, + {file = "nvidia_cublas_cu12-12.6.4.1-py3-none-win_amd64.whl", hash = "sha256:9e4fa264f4d8a4eb0cdbd34beadc029f453b3bafae02401e999cf3d5a5af75f8"}, +] + +[[package]] +name = "nvidia-cublas-cu12" +version = "12.8.4.1" +description = "CUBLAS native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0"}, + {file = "nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142"}, + {file = "nvidia_cublas_cu12-12.8.4.1-py3-none-win_amd64.whl", hash = "sha256:47e9b82132fa8d2b4944e708049229601448aaad7e6f296f630f2d1a32de35af"}, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.6.80" +description = "CUDA profiling tools runtime libs." +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:166ee35a3ff1587f2490364f90eeeb8da06cd867bd5b701bf7f9a02b78bc63fc"}, + {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_aarch64.whl", hash = "sha256:358b4a1d35370353d52e12f0a7d1769fc01ff74a191689d3870b2123156184c4"}, + {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6768bad6cab4f19e8292125e5f1ac8aa7d1718704012a0e3272a6f61c4bce132"}, + {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a3eff6cdfcc6a4c35db968a06fcadb061cbc7d6dde548609a941ff8701b98b73"}, + {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-win_amd64.whl", hash = "sha256:bbe6ae76e83ce5251b56e8c8e61a964f757175682bbad058b170b136266ab00a"}, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.8.90" +description = "CUDA profiling tools runtime libs." +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed"}, + {file = "nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182"}, + {file = "nvidia_cuda_cupti_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:bb479dcdf7e6d4f8b0b01b115260399bf34154a1a2e9fe11c85c517d87efd98e"}, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.6.77" +description = "NVRTC native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_cuda_nvrtc_cu12-12.6.77-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5847f1d6e5b757f1d2b3991a01082a44aad6f10ab3c5c0213fa3e25bddc25a13"}, + {file = "nvidia_cuda_nvrtc_cu12-12.6.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:35b0cc6ee3a9636d5409133e79273ce1f3fd087abb0532d2d2e8fff1fe9efc53"}, + {file = "nvidia_cuda_nvrtc_cu12-12.6.77-py3-none-win_amd64.whl", hash = "sha256:f7007dbd914c56bd80ea31bc43e8e149da38f68158f423ba845fc3292684e45a"}, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.8.93" +description = "NVRTC native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994"}, + {file = "nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8"}, + {file = "nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-win_amd64.whl", hash = "sha256:7a4b6b2904850fe78e0bd179c4b655c404d4bb799ef03ddc60804247099ae909"}, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.6.77" +description = "CUDA Runtime native Libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6116fad3e049e04791c0256a9778c16237837c08b27ed8c8401e2e45de8d60cd"}, + {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d461264ecb429c84c8879a7153499ddc7b19b5f8d84c204307491989a365588e"}, + {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ba3b56a4f896141e25e19ab287cd71e52a6a0f4b29d0d31609f60e3b4d5219b7"}, + {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a84d15d5e1da416dd4774cb42edf5e954a3e60cc945698dc1d5be02321c44dc8"}, + {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-win_amd64.whl", hash = "sha256:86c58044c824bf3c173c49a2dbc7a6c8b53cb4e4dca50068be0bf64e9dab3f7f"}, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.8.90" +description = "CUDA Runtime native Libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d"}, + {file = "nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90"}, + {file = "nvidia_cuda_runtime_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:c0c6027f01505bfed6c3b21ec546f69c687689aad5f1a377554bc6ca4aa993a8"}, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.5.1.17" +description = "cuDNN runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_cudnn_cu12-9.5.1.17-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:9fd4584468533c61873e5fda8ca41bac3a38bcb2d12350830c69b0a96a7e4def"}, + {file = "nvidia_cudnn_cu12-9.5.1.17-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:30ac3869f6db17d170e0e556dd6cc5eee02647abc31ca856634d5a40f82c15b2"}, + {file = "nvidia_cudnn_cu12-9.5.1.17-py3-none-win_amd64.whl", hash = "sha256:d7af0f8a4f3b4b9dbb3122f2ef553b45694ed9c384d5a75bab197b8eefb79ab8"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = "*" + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.10.2.21" +description = "cuDNN runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8"}, + {file = "nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8"}, + {file = "nvidia_cudnn_cu12-9.10.2.21-py3-none-win_amd64.whl", hash = "sha256:c6288de7d63e6cf62988f0923f96dc339cea362decb1bf5b3141883392a7d65e"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = "*" + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.3.0.4" +description = "CUFFT native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d16079550df460376455cba121db6564089176d9bac9e4f360493ca4741b22a6"}, + {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8510990de9f96c803a051822618d42bf6cb8f069ff3f48d93a8486efdacb48fb"}, + {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ccba62eb9cef5559abd5e0d54ceed2d9934030f51163df018532142a8ec533e5"}, + {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_x86_64.whl", hash = "sha256:768160ac89f6f7b459bee747e8d175dbf53619cfe74b2a5636264163138013ca"}, + {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-win_amd64.whl", hash = "sha256:6048ebddfb90d09d2707efb1fd78d4e3a77cb3ae4dc60e19aab6be0ece2ae464"}, +] + +[package.dependencies] +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.3.3.83" +description = "CUFFT native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a"}, + {file = "nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74"}, + {file = "nvidia_cufft_cu12-11.3.3.83-py3-none-win_amd64.whl", hash = "sha256:7a64a98ef2a7c47f905aaf8931b69a3a43f27c55530c698bb2ed7c75c0b42cb7"}, +] + +[package.dependencies] +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.11.1.6" +description = "cuFile GPUDirect libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_cufile_cu12-1.11.1.6-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc23469d1c7e52ce6c1d55253273d32c565dd22068647f3aa59b3c6b005bf159"}, + {file = "nvidia_cufile_cu12-1.11.1.6-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:8f57a0051dcf2543f6dc2b98a98cb2719c37d3cee1baba8965d57f3bbc90d4db"}, +] + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.13.1.3" +description = "cuFile GPUDirect libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc"}, + {file = "nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a"}, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.7.77" +description = "CURAND native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_curand_cu12-10.3.7.77-py3-none-manylinux2014_aarch64.whl", hash = "sha256:6e82df077060ea28e37f48a3ec442a8f47690c7499bff392a5938614b56c98d8"}, + {file = "nvidia_curand_cu12-10.3.7.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a42cd1344297f70b9e39a1e4f467a4e1c10f1da54ff7a85c12197f6c652c8bdf"}, + {file = "nvidia_curand_cu12-10.3.7.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:99f1a32f1ac2bd134897fc7a203f779303261268a65762a623bf30cc9fe79117"}, + {file = "nvidia_curand_cu12-10.3.7.77-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:7b2ed8e95595c3591d984ea3603dd66fe6ce6812b886d59049988a712ed06b6e"}, + {file = "nvidia_curand_cu12-10.3.7.77-py3-none-win_amd64.whl", hash = "sha256:6d6d935ffba0f3d439b7cd968192ff068fafd9018dbf1b85b37261b13cfc9905"}, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.9.90" +description = "CURAND native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd"}, + {file = "nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9"}, + {file = "nvidia_curand_cu12-10.3.9.90-py3-none-win_amd64.whl", hash = "sha256:f149a8ca457277da854f89cf282d6ef43176861926c7ac85b2a0fbd237c587ec"}, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.1.2" +description = "CUDA solver native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0ce237ef60acde1efc457335a2ddadfd7610b892d94efee7b776c64bb1cac9e0"}, + {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e9e49843a7707e42022babb9bcfa33c29857a93b88020c4e4434656a655b698c"}, + {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6cf28f17f64107a0c4d7802be5ff5537b2130bfc112f25d5a30df227058ca0e6"}, + {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dbbe4fc38ec1289c7e5230e16248365e375c3673c9c8bac5796e2e20db07f56e"}, + {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-win_amd64.whl", hash = "sha256:6813f9d8073f555444a8705f3ab0296d3e1cb37a16d694c5fc8b862a0d8706d7"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = "*" +nvidia-cusparse-cu12 = "*" +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.3.90" +description = "CUDA solver native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0"}, + {file = "nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450"}, + {file = "nvidia_cusolver_cu12-11.7.3.90-py3-none-win_amd64.whl", hash = "sha256:4a550db115fcabc4d495eb7d39ac8b58d4ab5d8e63274d3754df1c0ad6a22d34"}, +] + +[package.dependencies] +nvidia-cublas-cu12 = "*" +nvidia-cusparse-cu12 = "*" +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.4.2" +description = "CUSPARSE native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d25b62fb18751758fe3c93a4a08eff08effedfe4edf1c6bb5afd0890fe88f887"}, + {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7aa32fa5470cf754f72d1116c7cbc300b4e638d3ae5304cfa4a638a5b87161b1"}, + {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7556d9eca156e18184b94947ade0fba5bb47d69cec46bf8660fd2c71a4b48b73"}, + {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:23749a6571191a215cb74d1cdbff4a86e7b19f1200c071b3fcf844a5bea23a2f"}, + {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-win_amd64.whl", hash = "sha256:4acb8c08855a26d737398cba8fb6f8f5045d93f82612b4cfd84645a2332ccf20"}, +] + +[package.dependencies] +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.8.93" +description = "CUSPARSE native runtime libraries" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc"}, + {file = "nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b"}, + {file = "nvidia_cusparse_cu12-12.5.8.93-py3-none-win_amd64.whl", hash = "sha256:9a33604331cb2cac199f2e7f5104dfbb8a5a898c367a53dfda9ff2acb6b6b4dd"}, +] + +[package.dependencies] +nvidia-nvjitlink-cu12 = "*" + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.6.3" +description = "NVIDIA cuSPARSELt" +optional = false +python-versions = "*" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_cusparselt_cu12-0.6.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8371549623ba601a06322af2133c4a44350575f5a3108fb75f3ef20b822ad5f1"}, + {file = "nvidia_cusparselt_cu12-0.6.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e5c8a26c36445dd2e6812f1177978a24e2d37cacce7e090f297a688d1ec44f46"}, + {file = "nvidia_cusparselt_cu12-0.6.3-py3-none-win_amd64.whl", hash = "sha256:3b325bcbd9b754ba43df5a311488fca11a6b5dc3d11df4d190c000cf1a0765c7"}, +] + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.7.1" +description = "NVIDIA cuSPARSELt" +optional = false +python-versions = "*" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5"}, + {file = "nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623"}, + {file = "nvidia_cusparselt_cu12-0.7.1-py3-none-win_amd64.whl", hash = "sha256:f67fbb5831940ec829c9117b7f33807db9f9678dc2a617fbe781cac17b4e1075"}, +] + +[[package]] +name = "nvidia-ml-py" +version = "12.575.51" +description = "Python Bindings for the NVIDIA Management Library" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "nvidia_ml_py-12.575.51-py3-none-any.whl", hash = "sha256:eb8641800d98ce40a22f479873f34b482e214a7e80349c63be51c3919845446e"}, + {file = "nvidia_ml_py-12.575.51.tar.gz", hash = "sha256:6490e93fea99eb4e966327ae18c6eec6256194c921f23459c8767aee28c54581"}, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.26.2" +description = "NVIDIA Collective Communication Library (NCCL) Runtime" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_nccl_cu12-2.26.2-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c196e95e832ad30fbbb50381eb3cbd1fadd5675e587a548563993609af19522"}, + {file = "nvidia_nccl_cu12-2.26.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:694cf3879a206553cc9d7dbda76b13efaf610fdb70a50cba303de1b0d1530ac6"}, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.27.3" +description = "NVIDIA Collective Communication Library (NCCL) Runtime" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_nccl_cu12-2.27.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9ddf1a245abc36c550870f26d537a9b6087fb2e2e3d6e0ef03374c6fd19d984f"}, + {file = "nvidia_nccl_cu12-2.27.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adf27ccf4238253e0b826bce3ff5fa532d65fc42322c8bfdfaf28024c0fbe039"}, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.6.85" +description = "Nvidia JIT LTO Library" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:eedc36df9e88b682efe4309aa16b5b4e78c2407eac59e8c10a6a47535164369a"}, + {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cf4eaa7d4b6b543ffd69d6abfb11efdeb2db48270d94dfd3a452c24150829e41"}, + {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-win_amd64.whl", hash = "sha256:e61120e52ed675747825cdd16febc6a0730537451d867ee58bee3853b1b13d1c"}, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.8.93" +description = "Nvidia JIT LTO Library" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88"}, + {file = "nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7"}, + {file = "nvidia_nvjitlink_cu12-12.8.93-py3-none-win_amd64.whl", hash = "sha256:bd93fbeeee850917903583587f4fc3a4eafa022e34572251368238ab5e6bd67f"}, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.6.77" +description = "NVIDIA Tools Extension" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f44f8d86bb7d5629988d61c8d3ae61dddb2015dee142740536bc7481b022fe4b"}, + {file = "nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_aarch64.whl", hash = "sha256:adcaabb9d436c9761fca2b13959a2d237c5f9fd406c8e4b723c695409ff88059"}, + {file = "nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b90bed3df379fa79afbd21be8e04a0314336b8ae16768b58f2d34cb1d04cd7d2"}, + {file = "nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6574241a3ec5fdc9334353ab8c479fe75841dbe8f4532a8fc97ce63503330ba1"}, + {file = "nvidia_nvtx_cu12-12.6.77-py3-none-win_amd64.whl", hash = "sha256:2fb11a4af04a5e6c84073e6404d26588a34afd35379f0855a99797897efa75c0"}, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.8.90" +description = "NVIDIA Tools Extension" +optional = false +python-versions = ">=3" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615"}, + {file = "nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f"}, + {file = "nvidia_nvtx_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:619c8304aedc69f02ea82dd244541a83c3d9d40993381b3b590f1adaed3db41e"}, +] + +[[package]] +name = "packaging" +version = "25.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["main", "benchmarks", "dev", "docs"] +files = [ + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, +] + +[[package]] +name = "pandas" +version = "2.3.2" +description = "Powerful data structures for data analysis, time series, and statistics" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pandas-2.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52bc29a946304c360561974c6542d1dd628ddafa69134a7131fdfd6a5d7a1a35"}, + {file = "pandas-2.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:220cc5c35ffaa764dd5bb17cf42df283b5cb7fdf49e10a7b053a06c9cb48ee2b"}, + {file = "pandas-2.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42c05e15111221384019897df20c6fe893b2f697d03c811ee67ec9e0bb5a3424"}, + {file = "pandas-2.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc03acc273c5515ab69f898df99d9d4f12c4d70dbfc24c3acc6203751d0804cf"}, + {file = "pandas-2.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d25c20a03e8870f6339bcf67281b946bd20b86f1a544ebbebb87e66a8d642cba"}, + {file = "pandas-2.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21bb612d148bb5860b7eb2c10faacf1a810799245afd342cf297d7551513fbb6"}, + {file = "pandas-2.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:b62d586eb25cb8cb70a5746a378fc3194cb7f11ea77170d59f889f5dfe3cec7a"}, + {file = "pandas-2.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1333e9c299adcbb68ee89a9bb568fc3f20f9cbb419f1dd5225071e6cddb2a743"}, + {file = "pandas-2.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:76972bcbd7de8e91ad5f0ca884a9f2c477a2125354af624e022c49e5bd0dfff4"}, + {file = "pandas-2.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b98bdd7c456a05eef7cd21fd6b29e3ca243591fe531c62be94a2cc987efb5ac2"}, + {file = "pandas-2.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d81573b3f7db40d020983f78721e9bfc425f411e616ef019a10ebf597aedb2e"}, + {file = "pandas-2.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e190b738675a73b581736cc8ec71ae113d6c3768d0bd18bffa5b9a0927b0b6ea"}, + {file = "pandas-2.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c253828cb08f47488d60f43c5fc95114c771bbfff085da54bfc79cb4f9e3a372"}, + {file = "pandas-2.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:9467697b8083f9667b212633ad6aa4ab32436dcbaf4cd57325debb0ddef2012f"}, + {file = "pandas-2.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fbb977f802156e7a3f829e9d1d5398f6192375a3e2d1a9ee0803e35fe70a2b9"}, + {file = "pandas-2.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1b9b52693123dd234b7c985c68b709b0b009f4521000d0525f2b95c22f15944b"}, + {file = "pandas-2.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bd281310d4f412733f319a5bc552f86d62cddc5f51d2e392c8787335c994175"}, + {file = "pandas-2.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96d31a6b4354e3b9b8a2c848af75d31da390657e3ac6f30c05c82068b9ed79b9"}, + {file = "pandas-2.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:df4df0b9d02bb873a106971bb85d448378ef14b86ba96f035f50bbd3688456b4"}, + {file = "pandas-2.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:213a5adf93d020b74327cb2c1b842884dbdd37f895f42dcc2f09d451d949f811"}, + {file = "pandas-2.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c13b81a9347eb8c7548f53fd9a4f08d4dfe996836543f805c987bafa03317ae"}, + {file = "pandas-2.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0c6ecbac99a354a051ef21c5307601093cb9e0f4b1855984a084bfec9302699e"}, + {file = "pandas-2.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c6f048aa0fd080d6a06cc7e7537c09b53be6642d330ac6f54a600c3ace857ee9"}, + {file = "pandas-2.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0064187b80a5be6f2f9c9d6bdde29372468751dfa89f4211a3c5871854cfbf7a"}, + {file = "pandas-2.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ac8c320bded4718b298281339c1a50fb00a6ba78cb2a63521c39bec95b0209b"}, + {file = "pandas-2.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:114c2fe4f4328cf98ce5716d1532f3ab79c5919f95a9cfee81d9140064a2e4d6"}, + {file = "pandas-2.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:48fa91c4dfb3b2b9bfdb5c24cd3567575f4e13f9636810462ffed8925352be5a"}, + {file = "pandas-2.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:12d039facec710f7ba305786837d0225a3444af7bbd9c15c32ca2d40d157ed8b"}, + {file = "pandas-2.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c624b615ce97864eb588779ed4046186f967374185c047070545253a52ab2d57"}, + {file = "pandas-2.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0cee69d583b9b128823d9514171cabb6861e09409af805b54459bd0c821a35c2"}, + {file = "pandas-2.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2319656ed81124982900b4c37f0e0c58c015af9a7bbc62342ba5ad07ace82ba9"}, + {file = "pandas-2.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b37205ad6f00d52f16b6d09f406434ba928c1a1966e2771006a9033c736d30d2"}, + {file = "pandas-2.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:837248b4fc3a9b83b9c6214699a13f069dc13510a6a6d7f9ba33145d2841a012"}, + {file = "pandas-2.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d2c3554bd31b731cd6490d94a28f3abb8dd770634a9e06eb6d2911b9827db370"}, + {file = "pandas-2.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:88080a0ff8a55eac9c84e3ff3c7665b3b5476c6fbc484775ca1910ce1c3e0b87"}, + {file = "pandas-2.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d4a558c7620340a0931828d8065688b3cc5b4c8eb674bcaf33d18ff4a6870b4a"}, + {file = "pandas-2.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45178cf09d1858a1509dc73ec261bf5b25a625a389b65be2e47b559905f0ab6a"}, + {file = "pandas-2.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77cefe00e1b210f9c76c697fedd8fdb8d3dd86563e9c8adc9fa72b90f5e9e4c2"}, + {file = "pandas-2.3.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:13bd629c653856f00c53dc495191baa59bcafbbf54860a46ecc50d3a88421a96"}, + {file = "pandas-2.3.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:36d627906fd44b5fd63c943264e11e96e923f8de77d6016dc2f667b9ad193438"}, + {file = "pandas-2.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:a9d7ec92d71a420185dec44909c32e9a362248c4ae2238234b76d5be37f208cc"}, + {file = "pandas-2.3.2.tar.gz", hash = "sha256:ab7b58f8f82706890924ccdfb5f48002b83d2b5a3845976a9fb705d36c34dcdb"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.22.4", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, +] +python-dateutil = ">=2.8.2" +pytz = ">=2020.1" +tzdata = ">=2022.7" + +[package.extras] +all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"] +aws = ["s3fs (>=2022.11.0)"] +clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"] +compression = ["zstandard (>=0.19.0)"] +computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"] +consortium-standard = ["dataframe-api-compat (>=0.1.7)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"] +feather = ["pyarrow (>=10.0.1)"] +fss = ["fsspec (>=2022.11.0)"] +gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"] +hdf5 = ["tables (>=3.8.0)"] +html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"] +mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"] +parquet = ["pyarrow (>=10.0.1)"] +performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] +plot = ["matplotlib (>=3.6.3)"] +postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +pyarrow = ["pyarrow (>=10.0.1)"] +spss = ["pyreadstat (>=1.2.0)"] +sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.9.2)"] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "pillow" +version = "11.3.0" +description = "Python Imaging Library (Fork)" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"}, + {file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae"}, + {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9"}, + {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e"}, + {file = "pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6"}, + {file = "pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f"}, + {file = "pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f"}, + {file = "pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722"}, + {file = "pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f"}, + {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e"}, + {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94"}, + {file = "pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0"}, + {file = "pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac"}, + {file = "pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd"}, + {file = "pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4"}, + {file = "pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024"}, + {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809"}, + {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d"}, + {file = "pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149"}, + {file = "pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d"}, + {file = "pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f"}, + {file = "pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c"}, + {file = "pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8"}, + {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2"}, + {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b"}, + {file = "pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3"}, + {file = "pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51"}, + {file = "pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580"}, + {file = "pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e"}, + {file = "pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59"}, + {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe"}, + {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c"}, + {file = "pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788"}, + {file = "pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31"}, + {file = "pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e"}, + {file = "pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12"}, + {file = "pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77"}, + {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874"}, + {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a"}, + {file = "pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214"}, + {file = "pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635"}, + {file = "pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6"}, + {file = "pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae"}, + {file = "pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477"}, + {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50"}, + {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b"}, + {file = "pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12"}, + {file = "pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db"}, + {file = "pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa"}, + {file = "pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f"}, + {file = "pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a"}, + {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978"}, + {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d"}, + {file = "pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71"}, + {file = "pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada"}, + {file = "pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8"}, + {file = "pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] +test-arrow = ["pyarrow"] +tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"] +typing = ["typing-extensions ; python_version < \"3.10\""] +xmp = ["defusedxml"] + +[[package]] +name = "platformdirs" +version = "4.4.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.9" +groups = ["benchmarks", "dev"] +files = [ + {file = "platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85"}, + {file = "platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.14.1)"] + +[[package]] +name = "plotly" +version = "6.3.0" +description = "An open-source interactive data visualization library for Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "plotly-6.3.0-py3-none-any.whl", hash = "sha256:7ad806edce9d3cdd882eaebaf97c0c9e252043ed1ed3d382c3e3520ec07806d4"}, + {file = "plotly-6.3.0.tar.gz", hash = "sha256:8840a184d18ccae0f9189c2b9a2943923fd5cae7717b723f36eef78f444e5a73"}, +] + +[package.dependencies] +narwhals = ">=1.15.1" +packaging = "*" + +[package.extras] +dev = ["plotly[dev-optional]"] +dev-build = ["build", "jupyter", "plotly[dev-core]"] +dev-core = ["pytest", "requests", "ruff (==0.11.12)"] +dev-optional = ["anywidget", "colorcet", "fiona (<=1.9.6) ; python_version <= \"3.8\"", "geopandas", "inflect", "numpy", "orjson", "pandas", "pdfrw", "pillow", "plotly-geo", "plotly[dev-build]", "plotly[kaleido]", "polars[timezone]", "pyarrow", "pyshp", "pytz", "scikit-image", "scipy", "shapely", "statsmodels", "vaex ; python_version <= \"3.9\"", "xarray"] +express = ["numpy"] +kaleido = ["kaleido (>=1.0.0)"] + +[[package]] +name = "pluggy" +version = "1.6.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["coverage", "pytest", "pytest-benchmark"] + +[[package]] +name = "pre-commit" +version = "4.3.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pre_commit-4.3.0-py2.py3-none-any.whl", hash = "sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8"}, + {file = "pre_commit-4.3.0.tar.gz", hash = "sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + +[[package]] +name = "propcache" +version = "0.3.2" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770"}, + {file = "propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3"}, + {file = "propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614"}, + {file = "propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b"}, + {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c"}, + {file = "propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70"}, + {file = "propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9"}, + {file = "propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be"}, + {file = "propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f"}, + {file = "propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df"}, + {file = "propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf"}, + {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e"}, + {file = "propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897"}, + {file = "propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39"}, + {file = "propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10"}, + {file = "propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154"}, + {file = "propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67"}, + {file = "propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06"}, + {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1"}, + {file = "propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1"}, + {file = "propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c"}, + {file = "propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945"}, + {file = "propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252"}, + {file = "propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3"}, + {file = "propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206"}, + {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43"}, + {file = "propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02"}, + {file = "propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05"}, + {file = "propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b"}, + {file = "propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0"}, + {file = "propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725"}, + {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770"}, + {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330"}, + {file = "propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394"}, + {file = "propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198"}, + {file = "propcache-0.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a7fad897f14d92086d6b03fdd2eb844777b0c4d7ec5e3bac0fbae2ab0602bbe5"}, + {file = "propcache-0.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1f43837d4ca000243fd7fd6301947d7cb93360d03cd08369969450cc6b2ce3b4"}, + {file = "propcache-0.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:261df2e9474a5949c46e962065d88eb9b96ce0f2bd30e9d3136bcde84befd8f2"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e514326b79e51f0a177daab1052bc164d9d9e54133797a3a58d24c9c87a3fe6d"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4a996adb6904f85894570301939afeee65f072b4fd265ed7e569e8d9058e4ec"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76cace5d6b2a54e55b137669b30f31aa15977eeed390c7cbfb1dafa8dfe9a701"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31248e44b81d59d6addbb182c4720f90b44e1efdc19f58112a3c3a1615fb47ef"}, + {file = "propcache-0.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abb7fa19dbf88d3857363e0493b999b8011eea856b846305d8c0512dfdf8fbb1"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d81ac3ae39d38588ad0549e321e6f773a4e7cc68e7751524a22885d5bbadf886"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:cc2782eb0f7a16462285b6f8394bbbd0e1ee5f928034e941ffc444012224171b"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:db429c19a6c7e8a1c320e6a13c99799450f411b02251fb1b75e6217cf4a14fcb"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:21d8759141a9e00a681d35a1f160892a36fb6caa715ba0b832f7747da48fb6ea"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2ca6d378f09adb13837614ad2754fa8afaee330254f404299611bce41a8438cb"}, + {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:34a624af06c048946709f4278b4176470073deda88d91342665d95f7c6270fbe"}, + {file = "propcache-0.3.2-cp39-cp39-win32.whl", hash = "sha256:4ba3fef1c30f306b1c274ce0b8baaa2c3cdd91f645c48f06394068f37d3837a1"}, + {file = "propcache-0.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:7a2368eed65fc69a7a7a40b27f22e85e7627b74216f0846b04ba5c116e191ec9"}, + {file = "propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f"}, + {file = "propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168"}, +] + +[[package]] +name = "protobuf" +version = "6.32.0" +description = "" +optional = false +python-versions = ">=3.9" +groups = ["benchmarks"] +files = [ + {file = "protobuf-6.32.0-cp310-abi3-win32.whl", hash = "sha256:84f9e3c1ff6fb0308dbacb0950d8aa90694b0d0ee68e75719cb044b7078fe741"}, + {file = "protobuf-6.32.0-cp310-abi3-win_amd64.whl", hash = "sha256:a8bdbb2f009cfc22a36d031f22a625a38b615b5e19e558a7b756b3279723e68e"}, + {file = "protobuf-6.32.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d52691e5bee6c860fff9a1c86ad26a13afbeb4b168cd4445c922b7e2cf85aaf0"}, + {file = "protobuf-6.32.0-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:501fe6372fd1c8ea2a30b4d9be8f87955a64d6be9c88a973996cef5ef6f0abf1"}, + {file = "protobuf-6.32.0-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:75a2aab2bd1aeb1f5dc7c5f33bcb11d82ea8c055c9becbb41c26a8c43fd7092c"}, + {file = "protobuf-6.32.0-cp39-cp39-win32.whl", hash = "sha256:7db8ed09024f115ac877a1427557b838705359f047b2ff2f2b2364892d19dacb"}, + {file = "protobuf-6.32.0-cp39-cp39-win_amd64.whl", hash = "sha256:15eba1b86f193a407607112ceb9ea0ba9569aed24f93333fe9a497cf2fda37d3"}, + {file = "protobuf-6.32.0-py3-none-any.whl", hash = "sha256:ba377e5b67b908c8f3072a57b63e2c6a4cbd18aea4ed98d2584350dbf46f2783"}, + {file = "protobuf-6.32.0.tar.gz", hash = "sha256:a81439049127067fc49ec1d36e25c6ee1d1a2b7be930675f919258d03c04e7d2"}, +] + +[[package]] +name = "psutil" +version = "7.0.0" +description = "Cross-platform lib for process and system monitoring in Python. NOTE: the syntax of this script MUST be kept compatible with Python 2.7." +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {file = "psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25"}, + {file = "psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da"}, + {file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91"}, + {file = "psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34"}, + {file = "psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993"}, + {file = "psutil-7.0.0-cp36-cp36m-win32.whl", hash = "sha256:84df4eb63e16849689f76b1ffcb36db7b8de703d1bc1fe41773db487621b6c17"}, + {file = "psutil-7.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1e744154a6580bc968a0195fd25e80432d3afec619daf145b9e5ba16cc1d688e"}, + {file = "psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99"}, + {file = "psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553"}, + {file = "psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456"}, +] + +[package.extras] +dev = ["abi3audit", "black (==24.10.0)", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest", "pytest-cov", "pytest-xdist", "requests", "rstcheck", "ruff", "setuptools", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"] +test = ["pytest", "pytest-xdist", "setuptools"] + +[[package]] +name = "pyarrow" +version = "21.0.0" +description = "Python library for Apache Arrow" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pyarrow-21.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:e563271e2c5ff4d4a4cbeb2c83d5cf0d4938b891518e676025f7268c6fe5fe26"}, + {file = "pyarrow-21.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:fee33b0ca46f4c85443d6c450357101e47d53e6c3f008d658c27a2d020d44c79"}, + {file = "pyarrow-21.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:7be45519b830f7c24b21d630a31d48bcebfd5d4d7f9d3bdb49da9cdf6d764edb"}, + {file = "pyarrow-21.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:26bfd95f6bff443ceae63c65dc7e048670b7e98bc892210acba7e4995d3d4b51"}, + {file = "pyarrow-21.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bd04ec08f7f8bd113c55868bd3fc442a9db67c27af098c5f814a3091e71cc61a"}, + {file = "pyarrow-21.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9b0b14b49ac10654332a805aedfc0147fb3469cbf8ea951b3d040dab12372594"}, + {file = "pyarrow-21.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:9d9f8bcb4c3be7738add259738abdeddc363de1b80e3310e04067aa1ca596634"}, + {file = "pyarrow-21.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c077f48aab61738c237802836fc3844f85409a46015635198761b0d6a688f87b"}, + {file = "pyarrow-21.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:689f448066781856237eca8d1975b98cace19b8dd2ab6145bf49475478bcaa10"}, + {file = "pyarrow-21.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:479ee41399fcddc46159a551705b89c05f11e8b8cb8e968f7fec64f62d91985e"}, + {file = "pyarrow-21.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:40ebfcb54a4f11bcde86bc586cbd0272bac0d516cfa539c799c2453768477569"}, + {file = "pyarrow-21.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8d58d8497814274d3d20214fbb24abcad2f7e351474357d552a8d53bce70c70e"}, + {file = "pyarrow-21.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:585e7224f21124dd57836b1530ac8f2df2afc43c861d7bf3d58a4870c42ae36c"}, + {file = "pyarrow-21.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:555ca6935b2cbca2c0e932bedd853e9bc523098c39636de9ad4693b5b1df86d6"}, + {file = "pyarrow-21.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:3a302f0e0963db37e0a24a70c56cf91a4faa0bca51c23812279ca2e23481fccd"}, + {file = "pyarrow-21.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:b6b27cf01e243871390474a211a7922bfbe3bda21e39bc9160daf0da3fe48876"}, + {file = "pyarrow-21.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e72a8ec6b868e258a2cd2672d91f2860ad532d590ce94cdf7d5e7ec674ccf03d"}, + {file = "pyarrow-21.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b7ae0bbdc8c6674259b25bef5d2a1d6af5d39d7200c819cf99e07f7dfef1c51e"}, + {file = "pyarrow-21.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:58c30a1729f82d201627c173d91bd431db88ea74dcaa3885855bc6203e433b82"}, + {file = "pyarrow-21.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:072116f65604b822a7f22945a7a6e581cfa28e3454fdcc6939d4ff6090126623"}, + {file = "pyarrow-21.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf56ec8b0a5c8c9d7021d6fd754e688104f9ebebf1bf4449613c9531f5346a18"}, + {file = "pyarrow-21.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:e99310a4ebd4479bcd1964dff9e14af33746300cb014aa4a3781738ac63baf4a"}, + {file = "pyarrow-21.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:d2fe8e7f3ce329a71b7ddd7498b3cfac0eeb200c2789bd840234f0dc271a8efe"}, + {file = "pyarrow-21.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:f522e5709379d72fb3da7785aa489ff0bb87448a9dc5a75f45763a795a089ebd"}, + {file = "pyarrow-21.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:69cbbdf0631396e9925e048cfa5bce4e8c3d3b41562bbd70c685a8eb53a91e61"}, + {file = "pyarrow-21.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:731c7022587006b755d0bdb27626a1a3bb004bb56b11fb30d98b6c1b4718579d"}, + {file = "pyarrow-21.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dc56bc708f2d8ac71bd1dcb927e458c93cec10b98eb4120206a4091db7b67b99"}, + {file = "pyarrow-21.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:186aa00bca62139f75b7de8420f745f2af12941595bbbfa7ed3870ff63e25636"}, + {file = "pyarrow-21.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:a7a102574faa3f421141a64c10216e078df467ab9576684d5cd696952546e2da"}, + {file = "pyarrow-21.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:1e005378c4a2c6db3ada3ad4c217b381f6c886f0a80d6a316fe586b90f77efd7"}, + {file = "pyarrow-21.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:65f8e85f79031449ec8706b74504a316805217b35b6099155dd7e227eef0d4b6"}, + {file = "pyarrow-21.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:3a81486adc665c7eb1a2bde0224cfca6ceaba344a82a971ef059678417880eb8"}, + {file = "pyarrow-21.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fc0d2f88b81dcf3ccf9a6ae17f89183762c8a94a5bdcfa09e05cfe413acf0503"}, + {file = "pyarrow-21.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6299449adf89df38537837487a4f8d3bd91ec94354fdd2a7d30bc11c48ef6e79"}, + {file = "pyarrow-21.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:222c39e2c70113543982c6b34f3077962b44fca38c0bd9e68bb6781534425c10"}, + {file = "pyarrow-21.0.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:a7f6524e3747e35f80744537c78e7302cd41deee8baa668d56d55f77d9c464b3"}, + {file = "pyarrow-21.0.0-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:203003786c9fd253ebcafa44b03c06983c9c8d06c3145e37f1b76a1f317aeae1"}, + {file = "pyarrow-21.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3b4d97e297741796fead24867a8dabf86c87e4584ccc03167e4a811f50fdf74d"}, + {file = "pyarrow-21.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:898afce396b80fdda05e3086b4256f8677c671f7b1d27a6976fa011d3fd0a86e"}, + {file = "pyarrow-21.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:067c66ca29aaedae08218569a114e413b26e742171f526e828e1064fcdec13f4"}, + {file = "pyarrow-21.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0c4e75d13eb76295a49e0ea056eb18dbd87d81450bfeb8afa19a7e5a75ae2ad7"}, + {file = "pyarrow-21.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:cdc4c17afda4dab2a9c0b79148a43a7f4e1094916b3e18d8975bfd6d6d52241f"}, + {file = "pyarrow-21.0.0.tar.gz", hash = "sha256:5051f2dccf0e283ff56335760cbc8622cf52264d67e359d5569541ac11b6d5bc"}, +] + +[package.extras] +test = ["cffi", "hypothesis", "pandas", "pytest", "pytz"] + +[[package]] +name = "pycodestyle" +version = "2.9.1" +description = "Python style guide checker" +optional = false +python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, + {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, +] + +[[package]] +name = "pydantic" +version = "2.11.7" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.9" +groups = ["benchmarks"] +files = [ + {file = "pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b"}, + {file = "pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.33.2" +typing-extensions = ">=4.12.2" +typing-inspection = ">=0.4.0" + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.9" +groups = ["benchmarks"] +files = [ + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"}, + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"}, + {file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pyflakes" +version = "2.5.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.6" +groups = ["dev"] +files = [ + {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, + {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, +] + +[[package]] +name = "pygments" +version = "2.19.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +groups = ["dev", "docs"] +files = [ + {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, + {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pylint" +version = "2.17.4" +description = "python code static checker" +optional = false +python-versions = ">=3.7.2" +groups = ["dev"] +files = [ + {file = "pylint-2.17.4-py3-none-any.whl", hash = "sha256:7a1145fb08c251bdb5cca11739722ce64a63db479283d10ce718b2460e54123c"}, + {file = "pylint-2.17.4.tar.gz", hash = "sha256:5dcf1d9e19f41f38e4e85d10f511e5b9c35e1aa74251bf95cdd8cb23584e2db1"}, +] + +[package.dependencies] +astroid = ">=2.15.4,<=2.17.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = [ + {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, +] +isort = ">=4.2.5,<6" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +tomlkit = ">=0.10.1" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pynvml" +version = "12.0.0" +description = "Python utilities for the NVIDIA Management Library" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pynvml-12.0.0-py3-none-any.whl", hash = "sha256:fdff84b62a27dbe98e08e1a647eb77342bef1aebe0878bcd15e99a83fcbecb9e"}, + {file = "pynvml-12.0.0.tar.gz", hash = "sha256:299ce2451a6a17e6822d6faee750103e25b415f06f59abb8db65d30f794166f5"}, +] + +[package.dependencies] +nvidia-ml-py = ">=12.0.0,<13.0.0a0" + +[package.extras] +test = ["pytest (>=3.6)", "pytest-cov", "pytest-runner"] + +[[package]] +name = "pyparsing" +version = "3.2.3" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf"}, + {file = "pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pytest" +version = "8.4.1" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7"}, + {file = "pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c"}, +] + +[package.dependencies] +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} +iniconfig = ">=1" +packaging = ">=20" +pluggy = ">=1.5,<2" +pygments = ">=2.7.2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "6.2.1" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5"}, + {file = "pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2"}, +] + +[package.dependencies] +coverage = {version = ">=7.5", extras = ["toml"]} +pluggy = ">=1.2" +pytest = ">=6.2.5" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytest-mock" +version = "3.14.1" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "pytest_mock-3.14.1-py3-none-any.whl", hash = "sha256:178aefcd11307d874b4cd3100344e7e2d888d9791a6a1d9bfe90fbc1b74fd1d0"}, + {file = "pytest_mock-3.14.1.tar.gz", hash = "sha256:159e9edac4c451ce77a5cdb9fc5d1100708d2dd4ba3c3df572f14097351af80e"}, +] + +[package.dependencies] +pytest = ">=6.2.5" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + +[[package]] +name = "pytest-xdist" +version = "3.8.0" +description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88"}, + {file = "pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1"}, +] + +[package.dependencies] +execnet = ">=2.1" +pytest = ">=7.0.0" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2025.2" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"}, + {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"}, +] + +[[package]] +name = "pyupgrade" +version = "3.20.0" +description = "A tool to automatically upgrade syntax for newer versions." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pyupgrade-3.20.0-py2.py3-none-any.whl", hash = "sha256:cd5bf842b863f50adad324a01c30aef60b9f698a9814848094818659c92cd1f4"}, + {file = "pyupgrade-3.20.0.tar.gz", hash = "sha256:dd6a16c13fc1a7db45796008689a9a35420bd364d681430f640c5e54a3d351ea"}, +] + +[package.dependencies] +tokenize-rt = ">=6.1.0" + +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +groups = ["main", "benchmarks", "dev", "docs"] +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "regex" +version = "2025.9.1" +description = "Alternative regular expression module, to replace re." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "regex-2025.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5aa2a6a73bf218515484b36a0d20c6ad9dc63f6339ff6224147b0e2c095ee55"}, + {file = "regex-2025.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8c2ff5c01d5e47ad5fc9d31bcd61e78c2fa0068ed00cab86b7320214446da766"}, + {file = "regex-2025.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d49dc84e796b666181de8a9973284cad6616335f01b52bf099643253094920fc"}, + {file = "regex-2025.9.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9914fe1040874f83c15fcea86d94ea54091b0666eab330aaab69e30d106aabe"}, + {file = "regex-2025.9.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e71bceb3947362ec5eabd2ca0870bb78eae4edfc60c6c21495133c01b6cd2df4"}, + {file = "regex-2025.9.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:67a74456f410fe5e869239ee7a5423510fe5121549af133809d9591a8075893f"}, + {file = "regex-2025.9.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5c3b96ed0223b32dbdc53a83149b6de7ca3acd5acd9c8e64b42a166228abe29c"}, + {file = "regex-2025.9.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:113d5aa950f428faf46fd77d452df62ebb4cc6531cb619f6cc30a369d326bfbd"}, + {file = "regex-2025.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fcdeb38de4f7f3d69d798f4f371189061446792a84e7c92b50054c87aae9c07c"}, + {file = "regex-2025.9.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4bcdff370509164b67a6c8ec23c9fb40797b72a014766fdc159bb809bd74f7d8"}, + {file = "regex-2025.9.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:7383efdf6e8e8c61d85e00cfb2e2e18da1a621b8bfb4b0f1c2747db57b942b8f"}, + {file = "regex-2025.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1ec2bd3bdf0f73f7e9f48dca550ba7d973692d5e5e9a90ac42cc5f16c4432d8b"}, + {file = "regex-2025.9.1-cp310-cp310-win32.whl", hash = "sha256:9627e887116c4e9c0986d5c3b4f52bcfe3df09850b704f62ec3cbf177a0ae374"}, + {file = "regex-2025.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:94533e32dc0065eca43912ee6649c90ea0681d59f56d43c45b5bcda9a740b3dd"}, + {file = "regex-2025.9.1-cp310-cp310-win_arm64.whl", hash = "sha256:a874a61bb580d48642ffd338570ee24ab13fa023779190513fcacad104a6e251"}, + {file = "regex-2025.9.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e5bcf112b09bfd3646e4db6bf2e598534a17d502b0c01ea6550ba4eca780c5e6"}, + {file = "regex-2025.9.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:67a0295a3c31d675a9ee0238d20238ff10a9a2fdb7a1323c798fc7029578b15c"}, + {file = "regex-2025.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea8267fbadc7d4bd7c1301a50e85c2ff0de293ff9452a1a9f8d82c6cafe38179"}, + {file = "regex-2025.9.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6aeff21de7214d15e928fb5ce757f9495214367ba62875100d4c18d293750cc1"}, + {file = "regex-2025.9.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d89f1bbbbbc0885e1c230f7770d5e98f4f00b0ee85688c871d10df8b184a6323"}, + {file = "regex-2025.9.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca3affe8ddea498ba9d294ab05f5f2d3b5ad5d515bc0d4a9016dd592a03afe52"}, + {file = "regex-2025.9.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:91892a7a9f0a980e4c2c85dd19bc14de2b219a3a8867c4b5664b9f972dcc0c78"}, + {file = "regex-2025.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e1cb40406f4ae862710615f9f636c1e030fd6e6abe0e0f65f6a695a2721440c6"}, + {file = "regex-2025.9.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:94f6cff6f7e2149c7e6499a6ecd4695379eeda8ccbccb9726e8149f2fe382e92"}, + {file = "regex-2025.9.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6c0226fb322b82709e78c49cc33484206647f8a39954d7e9de1567f5399becd0"}, + {file = "regex-2025.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a12f59c7c380b4fcf7516e9cbb126f95b7a9518902bcf4a852423ff1dcd03e6a"}, + {file = "regex-2025.9.1-cp311-cp311-win32.whl", hash = "sha256:49865e78d147a7a4f143064488da5d549be6bfc3f2579e5044cac61f5c92edd4"}, + {file = "regex-2025.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:d34b901f6f2f02ef60f4ad3855d3a02378c65b094efc4b80388a3aeb700a5de7"}, + {file = "regex-2025.9.1-cp311-cp311-win_arm64.whl", hash = "sha256:47d7c2dab7e0b95b95fd580087b6ae196039d62306a592fa4e162e49004b6299"}, + {file = "regex-2025.9.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:84a25164bd8dcfa9f11c53f561ae9766e506e580b70279d05a7946510bdd6f6a"}, + {file = "regex-2025.9.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:645e88a73861c64c1af558dd12294fb4e67b5c1eae0096a60d7d8a2143a611c7"}, + {file = "regex-2025.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:10a450cba5cd5409526ee1d4449f42aad38dd83ac6948cbd6d7f71ca7018f7db"}, + {file = "regex-2025.9.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9dc5991592933a4192c166eeb67b29d9234f9c86344481173d1bc52f73a7104"}, + {file = "regex-2025.9.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a32291add816961aab472f4fad344c92871a2ee33c6c219b6598e98c1f0108f2"}, + {file = "regex-2025.9.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:588c161a68a383478e27442a678e3b197b13c5ba51dbba40c1ccb8c4c7bee9e9"}, + {file = "regex-2025.9.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47829ffaf652f30d579534da9085fe30c171fa2a6744a93d52ef7195dc38218b"}, + {file = "regex-2025.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e978e5a35b293ea43f140c92a3269b6ab13fe0a2bf8a881f7ac740f5a6ade85"}, + {file = "regex-2025.9.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4cf09903e72411f4bf3ac1eddd624ecfd423f14b2e4bf1c8b547b72f248b7bf7"}, + {file = "regex-2025.9.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d016b0f77be63e49613c9e26aaf4a242f196cd3d7a4f15898f5f0ab55c9b24d2"}, + {file = "regex-2025.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:656563e620de6908cd1c9d4f7b9e0777e3341ca7db9d4383bcaa44709c90281e"}, + {file = "regex-2025.9.1-cp312-cp312-win32.whl", hash = "sha256:df33f4ef07b68f7ab637b1dbd70accbf42ef0021c201660656601e8a9835de45"}, + {file = "regex-2025.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:5aba22dfbc60cda7c0853516104724dc904caa2db55f2c3e6e984eb858d3edf3"}, + {file = "regex-2025.9.1-cp312-cp312-win_arm64.whl", hash = "sha256:ec1efb4c25e1849c2685fa95da44bfde1b28c62d356f9c8d861d4dad89ed56e9"}, + {file = "regex-2025.9.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bc6834727d1b98d710a63e6c823edf6ffbf5792eba35d3fa119531349d4142ef"}, + {file = "regex-2025.9.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c3dc05b6d579875719bccc5f3037b4dc80433d64e94681a0061845bd8863c025"}, + {file = "regex-2025.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22213527df4c985ec4a729b055a8306272d41d2f45908d7bacb79be0fa7a75ad"}, + {file = "regex-2025.9.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8e3f6e3c5a5a1adc3f7ea1b5aec89abfc2f4fbfba55dafb4343cd1d084f715b2"}, + {file = "regex-2025.9.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bcb89c02a0d6c2bec9b0bb2d8c78782699afe8434493bfa6b4021cc51503f249"}, + {file = "regex-2025.9.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b0e2f95413eb0c651cd1516a670036315b91b71767af83bc8525350d4375ccba"}, + {file = "regex-2025.9.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09a41dc039e1c97d3c2ed3e26523f748e58c4de3ea7a31f95e1cf9ff973fff5a"}, + {file = "regex-2025.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4f0b4258b161094f66857a26ee938d3fe7b8a5063861e44571215c44fbf0e5df"}, + {file = "regex-2025.9.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bf70e18ac390e6977ea7e56f921768002cb0fa359c4199606c7219854ae332e0"}, + {file = "regex-2025.9.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b84036511e1d2bb0a4ff1aec26951caa2dea8772b223c9e8a19ed8885b32dbac"}, + {file = "regex-2025.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c2e05dcdfe224047f2a59e70408274c325d019aad96227ab959403ba7d58d2d7"}, + {file = "regex-2025.9.1-cp313-cp313-win32.whl", hash = "sha256:3b9a62107a7441b81ca98261808fed30ae36ba06c8b7ee435308806bd53c1ed8"}, + {file = "regex-2025.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:b38afecc10c177eb34cfae68d669d5161880849ba70c05cbfbe409f08cc939d7"}, + {file = "regex-2025.9.1-cp313-cp313-win_arm64.whl", hash = "sha256:ec329890ad5e7ed9fc292858554d28d58d56bf62cf964faf0aa57964b21155a0"}, + {file = "regex-2025.9.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:72fb7a016467d364546f22b5ae86c45680a4e0de6b2a6f67441d22172ff641f1"}, + {file = "regex-2025.9.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c9527fa74eba53f98ad86be2ba003b3ebe97e94b6eb2b916b31b5f055622ef03"}, + {file = "regex-2025.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c905d925d194c83a63f92422af7544ec188301451b292c8b487f0543726107ca"}, + {file = "regex-2025.9.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:74df7c74a63adcad314426b1f4ea6054a5ab25d05b0244f0c07ff9ce640fa597"}, + {file = "regex-2025.9.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4f6e935e98ea48c7a2e8be44494de337b57a204470e7f9c9c42f912c414cd6f5"}, + {file = "regex-2025.9.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4a62d033cd9ebefc7c5e466731a508dfabee827d80b13f455de68a50d3c2543d"}, + {file = "regex-2025.9.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef971ebf2b93bdc88d8337238be4dfb851cc97ed6808eb04870ef67589415171"}, + {file = "regex-2025.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d936a1db208bdca0eca1f2bb2c1ba1d8370b226785c1e6db76e32a228ffd0ad5"}, + {file = "regex-2025.9.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:7e786d9e4469698fc63815b8de08a89165a0aa851720eb99f5e0ea9d51dd2b6a"}, + {file = "regex-2025.9.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6b81d7dbc5466ad2c57ce3a0ddb717858fe1a29535c8866f8514d785fdb9fc5b"}, + {file = "regex-2025.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cd4890e184a6feb0ef195338a6ce68906a8903a0f2eb7e0ab727dbc0a3156273"}, + {file = "regex-2025.9.1-cp314-cp314-win32.whl", hash = "sha256:34679a86230e46164c9e0396b56cab13c0505972343880b9e705083cc5b8ec86"}, + {file = "regex-2025.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:a1196e530a6bfa5f4bde029ac5b0295a6ecfaaffbfffede4bbaf4061d9455b70"}, + {file = "regex-2025.9.1-cp314-cp314-win_arm64.whl", hash = "sha256:f46d525934871ea772930e997d577d48c6983e50f206ff7b66d4ac5f8941e993"}, + {file = "regex-2025.9.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a13d20007dce3c4b00af5d84f6c191ed1c0f70928c6d9b6cd7b8d2f125df7f46"}, + {file = "regex-2025.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d6b046b0a01cb713fd53ef36cb59db4b0062b343db28e83b52ac6aa01ee5b368"}, + {file = "regex-2025.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0fa9a7477288717f42dbd02ff5d13057549e9a8cdb81f224c313154cc10bab52"}, + {file = "regex-2025.9.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2b3ad150c6bc01a8cd5030040675060e2adbe6cbc50aadc4da42c6d32ec266e"}, + {file = "regex-2025.9.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:aa88d5a82dfe80deaf04e8c39c8b0ad166d5d527097eb9431cb932c44bf88715"}, + {file = "regex-2025.9.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6f1dae2cf6c2dbc6fd2526653692c144721b3cf3f769d2a3c3aa44d0f38b9a58"}, + {file = "regex-2025.9.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ff62a3022914fc19adaa76b65e03cf62bc67ea16326cbbeb170d280710a7d719"}, + {file = "regex-2025.9.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a34ef82216189d823bc82f614d1031cb0b919abef27cecfd7b07d1e9a8bdeeb4"}, + {file = "regex-2025.9.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6d40e6b49daae9ebbd7fa4e600697372cba85b826592408600068e83a3c47211"}, + {file = "regex-2025.9.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:0aeb0fe80331059c152a002142699a89bf3e44352aee28261315df0c9874759b"}, + {file = "regex-2025.9.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:a90014d29cb3098403d82a879105d1418edbbdf948540297435ea6e377023ea7"}, + {file = "regex-2025.9.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6ff623271e0b0cc5a95b802666bbd70f17ddd641582d65b10fb260cc0c003529"}, + {file = "regex-2025.9.1-cp39-cp39-win32.whl", hash = "sha256:d161bfdeabe236290adfd8c7588da7f835d67e9e7bf2945f1e9e120622839ba6"}, + {file = "regex-2025.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:43ebc77a7dfe36661192afd8d7df5e8be81ec32d2ad0c65b536f66ebfec3dece"}, + {file = "regex-2025.9.1-cp39-cp39-win_arm64.whl", hash = "sha256:5d74b557cf5554001a869cda60b9a619be307df4d10155894aeaad3ee67c9899"}, + {file = "regex-2025.9.1.tar.gz", hash = "sha256:88ac07b38d20b54d79e704e38aa3bd2c0f8027432164226bdee201a1c0c9c9ff"}, +] + +[[package]] +name = "requests" +version = "2.32.5" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.9" +groups = ["main", "benchmarks", "docs"] +files = [ + {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, + {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset_normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rich" +version = "14.1.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.8.0" +groups = ["dev"] +files = [ + {file = "rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f"}, + {file = "rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "roman-numerals-py" +version = "3.1.0" +description = "Manipulate well-formed Roman numerals" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c"}, + {file = "roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d"}, +] + +[package.extras] +lint = ["mypy (==1.15.0)", "pyright (==1.1.394)", "ruff (==0.9.7)"] +test = ["pytest (>=8)"] + +[[package]] +name = "rouge" +version = "1.0.1" +description = "Full Python ROUGE Score Implementation (not a wrapper)" +optional = false +python-versions = "*" +groups = ["main"] +files = [ + {file = "rouge-1.0.1-py3-none-any.whl", hash = "sha256:28d118536e8c774dc47d1d15ec266479b4dd0914c4672ce117d4002789bdc644"}, + {file = "rouge-1.0.1.tar.gz", hash = "sha256:12b48346ca47d6bcf3c45061f315452b9ccec0620ee895ec85b7efc3d54aae34"}, +] + +[package.dependencies] +six = "*" + +[[package]] +name = "safetensors" +version = "0.6.2" +description = "" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "safetensors-0.6.2-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:9c85ede8ec58f120bad982ec47746981e210492a6db876882aa021446af8ffba"}, + {file = "safetensors-0.6.2-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d6675cf4b39c98dbd7d940598028f3742e0375a6b4d4277e76beb0c35f4b843b"}, + {file = "safetensors-0.6.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d2d2b3ce1e2509c68932ca03ab8f20570920cd9754b05063d4368ee52833ecd"}, + {file = "safetensors-0.6.2-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:93de35a18f46b0f5a6a1f9e26d91b442094f2df02e9fd7acf224cfec4238821a"}, + {file = "safetensors-0.6.2-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89a89b505f335640f9120fac65ddeb83e40f1fd081cb8ed88b505bdccec8d0a1"}, + {file = "safetensors-0.6.2-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fc4d0d0b937e04bdf2ae6f70cd3ad51328635fe0e6214aa1fc811f3b576b3bda"}, + {file = "safetensors-0.6.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8045db2c872db8f4cbe3faa0495932d89c38c899c603f21e9b6486951a5ecb8f"}, + {file = "safetensors-0.6.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:81e67e8bab9878bb568cffbc5f5e655adb38d2418351dc0859ccac158f753e19"}, + {file = "safetensors-0.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b0e4d029ab0a0e0e4fdf142b194514695b1d7d3735503ba700cf36d0fc7136ce"}, + {file = "safetensors-0.6.2-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:fa48268185c52bfe8771e46325a1e21d317207bcabcb72e65c6e28e9ffeb29c7"}, + {file = "safetensors-0.6.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:d83c20c12c2d2f465997c51b7ecb00e407e5f94d7dec3ea0cc11d86f60d3fde5"}, + {file = "safetensors-0.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d944cea65fad0ead848b6ec2c37cc0b197194bec228f8020054742190e9312ac"}, + {file = "safetensors-0.6.2-cp38-abi3-win32.whl", hash = "sha256:cab75ca7c064d3911411461151cb69380c9225798a20e712b102edda2542ddb1"}, + {file = "safetensors-0.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:c7b214870df923cbc1593c3faee16bec59ea462758699bd3fee399d00aac072c"}, + {file = "safetensors-0.6.2.tar.gz", hash = "sha256:43ff2aa0e6fa2dc3ea5524ac7ad93a9839256b8703761e76e2d0b2a3fa4f15d9"}, +] + +[package.extras] +all = ["safetensors[jax]", "safetensors[numpy]", "safetensors[paddlepaddle]", "safetensors[pinned-tf]", "safetensors[quality]", "safetensors[testing]", "safetensors[torch]"] +dev = ["safetensors[all]"] +jax = ["flax (>=0.6.3)", "jax (>=0.3.25)", "jaxlib (>=0.3.25)", "safetensors[numpy]"] +mlx = ["mlx (>=0.0.9)"] +numpy = ["numpy (>=1.21.6)"] +paddlepaddle = ["paddlepaddle (>=2.4.1)", "safetensors[numpy]"] +pinned-tf = ["safetensors[numpy]", "tensorflow (==2.18.0)"] +quality = ["ruff"] +tensorflow = ["safetensors[numpy]", "tensorflow (>=2.11.0)"] +testing = ["h5py (>=3.7.0)", "huggingface-hub (>=0.12.1)", "hypothesis (>=6.70.2)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "safetensors[numpy]", "setuptools-rust (>=1.5.2)"] +testingfree = ["huggingface-hub (>=0.12.1)", "hypothesis (>=6.70.2)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "safetensors[numpy]", "setuptools-rust (>=1.5.2)"] +torch = ["safetensors[numpy]", "torch (>=1.10)"] + +[[package]] +name = "scikit-learn" +version = "1.6.1" +description = "A set of python modules for machine learning and data mining" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version < \"3.11\"" +files = [ + {file = "scikit_learn-1.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d056391530ccd1e501056160e3c9673b4da4805eb67eb2bdf4e983e1f9c9204e"}, + {file = "scikit_learn-1.6.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0c8d036eb937dbb568c6242fa598d551d88fb4399c0344d95c001980ec1c7d36"}, + {file = "scikit_learn-1.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8634c4bd21a2a813e0a7e3900464e6d593162a29dd35d25bdf0103b3fce60ed5"}, + {file = "scikit_learn-1.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:775da975a471c4f6f467725dff0ced5c7ac7bda5e9316b260225b48475279a1b"}, + {file = "scikit_learn-1.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:8a600c31592bd7dab31e1c61b9bbd6dea1b3433e67d264d17ce1017dbdce8002"}, + {file = "scikit_learn-1.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:72abc587c75234935e97d09aa4913a82f7b03ee0b74111dcc2881cba3c5a7b33"}, + {file = "scikit_learn-1.6.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:b3b00cdc8f1317b5f33191df1386c0befd16625f49d979fe77a8d44cae82410d"}, + {file = "scikit_learn-1.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc4765af3386811c3ca21638f63b9cf5ecf66261cc4815c1db3f1e7dc7b79db2"}, + {file = "scikit_learn-1.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25fc636bdaf1cc2f4a124a116312d837148b5e10872147bdaf4887926b8c03d8"}, + {file = "scikit_learn-1.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:fa909b1a36e000a03c382aade0bd2063fd5680ff8b8e501660c0f59f021a6415"}, + {file = "scikit_learn-1.6.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:926f207c804104677af4857b2c609940b743d04c4c35ce0ddc8ff4f053cddc1b"}, + {file = "scikit_learn-1.6.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:2c2cae262064e6a9b77eee1c8e768fc46aa0b8338c6a8297b9b6759720ec0ff2"}, + {file = "scikit_learn-1.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1061b7c028a8663fb9a1a1baf9317b64a257fcb036dae5c8752b2abef31d136f"}, + {file = "scikit_learn-1.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e69fab4ebfc9c9b580a7a80111b43d214ab06250f8a7ef590a4edf72464dd86"}, + {file = "scikit_learn-1.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:70b1d7e85b1c96383f872a519b3375f92f14731e279a7b4c6cfd650cf5dffc52"}, + {file = "scikit_learn-1.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ffa1e9e25b3d93990e74a4be2c2fc61ee5af85811562f1288d5d055880c4322"}, + {file = "scikit_learn-1.6.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:dc5cf3d68c5a20ad6d571584c0750ec641cc46aeef1c1507be51300e6003a7e1"}, + {file = "scikit_learn-1.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c06beb2e839ecc641366000ca84f3cf6fa9faa1777e29cf0c04be6e4d096a348"}, + {file = "scikit_learn-1.6.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8ca8cb270fee8f1f76fa9bfd5c3507d60c6438bbee5687f81042e2bb98e5a97"}, + {file = "scikit_learn-1.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:7a1c43c8ec9fde528d664d947dc4c0789be4077a3647f232869f41d9bf50e0fb"}, + {file = "scikit_learn-1.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a17c1dea1d56dcda2fac315712f3651a1fea86565b64b48fa1bc090249cbf236"}, + {file = "scikit_learn-1.6.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6a7aa5f9908f0f28f4edaa6963c0a6183f1911e63a69aa03782f0d924c830a35"}, + {file = "scikit_learn-1.6.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0650e730afb87402baa88afbf31c07b84c98272622aaba002559b614600ca691"}, + {file = "scikit_learn-1.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:3f59fe08dc03ea158605170eb52b22a105f238a5d512c4470ddeca71feae8e5f"}, + {file = "scikit_learn-1.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6849dd3234e87f55dce1db34c89a810b489ead832aaf4d4550b7ea85628be6c1"}, + {file = "scikit_learn-1.6.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:e7be3fa5d2eb9be7d77c3734ff1d599151bb523674be9b834e8da6abe132f44e"}, + {file = "scikit_learn-1.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44a17798172df1d3c1065e8fcf9019183f06c87609b49a124ebdf57ae6cb0107"}, + {file = "scikit_learn-1.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b7a3b86e411e4bce21186e1c180d792f3d99223dcfa3b4f597ecc92fa1a422"}, + {file = "scikit_learn-1.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:7a73d457070e3318e32bdb3aa79a8d990474f19035464dfd8bede2883ab5dc3b"}, + {file = "scikit_learn-1.6.1.tar.gz", hash = "sha256:b4fc2525eca2c69a59260f583c56a7557c6ccdf8deafdba6e060f94c1c59738e"}, +] + +[package.dependencies] +joblib = ">=1.2.0" +numpy = ">=1.19.5" +scipy = ">=1.6.0" +threadpoolctl = ">=3.1.0" + +[package.extras] +benchmark = ["matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "pandas (>=1.1.5)"] +build = ["cython (>=3.0.10)", "meson-python (>=0.16.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)"] +docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.3.4)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-design (>=0.6.0)", "sphinx-gallery (>=0.17.1)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)", "towncrier (>=24.8.0)"] +examples = ["matplotlib (>=3.3.4)", "pandas (>=1.1.5)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.17.2)", "seaborn (>=0.9.0)"] +install = ["joblib (>=1.2.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)", "threadpoolctl (>=3.1.0)"] +maintenance = ["conda-lock (==2.5.6)"] +tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.5.1)", "scikit-image (>=0.17.2)"] + +[[package]] +name = "scikit-learn" +version = "1.7.1" +description = "A set of python modules for machine learning and data mining" +optional = false +python-versions = ">=3.10" +groups = ["main"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "scikit_learn-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:406204dd4004f0517f0b23cf4b28c6245cbd51ab1b6b78153bc784def214946d"}, + {file = "scikit_learn-1.7.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:16af2e44164f05d04337fd1fc3ae7c4ea61fd9b0d527e22665346336920fe0e1"}, + {file = "scikit_learn-1.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2f2e78e56a40c7587dea9a28dc4a49500fa2ead366869418c66f0fd75b80885c"}, + {file = "scikit_learn-1.7.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b62b76ad408a821475b43b7bb90a9b1c9a4d8d125d505c2df0539f06d6e631b1"}, + {file = "scikit_learn-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:9963b065677a4ce295e8ccdee80a1dd62b37249e667095039adcd5bce6e90deb"}, + {file = "scikit_learn-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90c8494ea23e24c0fb371afc474618c1019dc152ce4a10e4607e62196113851b"}, + {file = "scikit_learn-1.7.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:bb870c0daf3bf3be145ec51df8ac84720d9972170786601039f024bf6d61a518"}, + {file = "scikit_learn-1.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:40daccd1b5623f39e8943ab39735cadf0bdce80e67cdca2adcb5426e987320a8"}, + {file = "scikit_learn-1.7.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:30d1f413cfc0aa5a99132a554f1d80517563c34a9d3e7c118fde2d273c6fe0f7"}, + {file = "scikit_learn-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:c711d652829a1805a95d7fe96654604a8f16eab5a9e9ad87b3e60173415cb650"}, + {file = "scikit_learn-1.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3cee419b49b5bbae8796ecd690f97aa412ef1674410c23fc3257c6b8b85b8087"}, + {file = "scikit_learn-1.7.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:2fd8b8d35817b0d9ebf0b576f7d5ffbbabdb55536b0655a8aaae629d7ffd2e1f"}, + {file = "scikit_learn-1.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:588410fa19a96a69763202f1d6b7b91d5d7a5d73be36e189bc6396bfb355bd87"}, + {file = "scikit_learn-1.7.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e3142f0abe1ad1d1c31a2ae987621e41f6b578144a911ff4ac94781a583adad7"}, + {file = "scikit_learn-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:3ddd9092c1bd469acab337d87930067c87eac6bd544f8d5027430983f1e1ae88"}, + {file = "scikit_learn-1.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b7839687fa46d02e01035ad775982f2470be2668e13ddd151f0f55a5bf123bae"}, + {file = "scikit_learn-1.7.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:a10f276639195a96c86aa572ee0698ad64ee939a7b042060b98bd1930c261d10"}, + {file = "scikit_learn-1.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:13679981fdaebc10cc4c13c43344416a86fcbc61449cb3e6517e1df9d12c8309"}, + {file = "scikit_learn-1.7.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f1262883c6a63f067a980a8cdd2d2e7f2513dddcef6a9eaada6416a7a7cbe43"}, + {file = "scikit_learn-1.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca6d31fb10e04d50bfd2b50d66744729dbb512d4efd0223b864e2fdbfc4cee11"}, + {file = "scikit_learn-1.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:781674d096303cfe3d351ae6963ff7c958db61cde3421cd490e3a5a58f2a94ae"}, + {file = "scikit_learn-1.7.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:10679f7f125fe7ecd5fad37dd1aa2daae7e3ad8df7f3eefa08901b8254b3e12c"}, + {file = "scikit_learn-1.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1f812729e38c8cb37f760dce71a9b83ccfb04f59b3dca7c6079dcdc60544fa9e"}, + {file = "scikit_learn-1.7.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:88e1a20131cf741b84b89567e1717f27a2ced228e0f29103426102bc2e3b8ef7"}, + {file = "scikit_learn-1.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b1bd1d919210b6a10b7554b717c9000b5485aa95a1d0f177ae0d7ee8ec750da5"}, + {file = "scikit_learn-1.7.1.tar.gz", hash = "sha256:24b3f1e976a4665aa74ee0fcaac2b8fccc6ae77c8e07ab25da3ba6d3292b9802"}, +] + +[package.dependencies] +joblib = ">=1.2.0" +numpy = ">=1.22.0" +scipy = ">=1.8.0" +threadpoolctl = ">=3.1.0" + +[package.extras] +benchmark = ["matplotlib (>=3.5.0)", "memory_profiler (>=0.57.0)", "pandas (>=1.4.0)"] +build = ["cython (>=3.0.10)", "meson-python (>=0.17.1)", "numpy (>=1.22.0)", "scipy (>=1.8.0)"] +docs = ["Pillow (>=8.4.0)", "matplotlib (>=3.5.0)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.4.0)", "plotly (>=5.14.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.19.0)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-design (>=0.6.0)", "sphinx-gallery (>=0.17.1)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)", "towncrier (>=24.8.0)"] +examples = ["matplotlib (>=3.5.0)", "pandas (>=1.4.0)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.19.0)", "seaborn (>=0.9.0)"] +install = ["joblib (>=1.2.0)", "numpy (>=1.22.0)", "scipy (>=1.8.0)", "threadpoolctl (>=3.1.0)"] +maintenance = ["conda-lock (==3.0.1)"] +tests = ["matplotlib (>=3.5.0)", "mypy (>=1.15)", "numpydoc (>=1.2.0)", "pandas (>=1.4.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pyamg (>=4.2.1)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.11.7)", "scikit-image (>=0.19.0)"] + +[[package]] +name = "scipy" +version = "1.13.1" +description = "Fundamental algorithms for scientific computing in Python" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "python_version < \"3.11\"" +files = [ + {file = "scipy-1.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:20335853b85e9a49ff7572ab453794298bcf0354d8068c5f6775a0eabf350aca"}, + {file = "scipy-1.13.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d605e9c23906d1994f55ace80e0125c587f96c020037ea6aa98d01b4bd2e222f"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfa31f1def5c819b19ecc3a8b52d28ffdcc7ed52bb20c9a7589669dd3c250989"}, + {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26264b282b9da0952a024ae34710c2aff7d27480ee91a2e82b7b7073c24722f"}, + {file = "scipy-1.13.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eccfa1906eacc02de42d70ef4aecea45415f5be17e72b61bafcfd329bdc52e94"}, + {file = "scipy-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:2831f0dc9c5ea9edd6e51e6e769b655f08ec6db6e2e10f86ef39bd32eb11da54"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27e52b09c0d3a1d5b63e1105f24177e544a222b43611aaf5bc44d4a0979e32f9"}, + {file = "scipy-1.13.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:54f430b00f0133e2224c3ba42b805bfd0086fe488835effa33fa291561932326"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89369d27f9e7b0884ae559a3a956e77c02114cc60a6058b4e5011572eea9299"}, + {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a78b4b3345f1b6f68a763c6e25c0c9a23a9fd0f39f5f3d200efe8feda560a5fa"}, + {file = "scipy-1.13.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45484bee6d65633752c490404513b9ef02475b4284c4cfab0ef946def50b3f59"}, + {file = "scipy-1.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:5713f62f781eebd8d597eb3f88b8bf9274e79eeabf63afb4a737abc6c84ad37b"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d72782f39716b2b3509cd7c33cdc08c96f2f4d2b06d51e52fb45a19ca0c86a1"}, + {file = "scipy-1.13.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:017367484ce5498445aade74b1d5ab377acdc65e27095155e448c88497755a5d"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:949ae67db5fa78a86e8fa644b9a6b07252f449dcf74247108c50e1d20d2b4627"}, + {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3ade0e53bc1f21358aa74ff4830235d716211d7d077e340c7349bc3542e884"}, + {file = "scipy-1.13.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2ac65fb503dad64218c228e2dc2d0a0193f7904747db43014645ae139c8fad16"}, + {file = "scipy-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdd7dacfb95fea358916410ec61bbc20440f7860333aee6d882bb8046264e949"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:436bbb42a94a8aeef855d755ce5a465479c721e9d684de76bf61a62e7c2b81d5"}, + {file = "scipy-1.13.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:8335549ebbca860c52bf3d02f80784e91a004b71b059e3eea9678ba994796a24"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d533654b7d221a6a97304ab63c41c96473ff04459e404b83275b60aa8f4b7004"}, + {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637e98dcf185ba7f8e663e122ebf908c4702420477ae52a04f9908707456ba4d"}, + {file = "scipy-1.13.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a014c2b3697bde71724244f63de2476925596c24285c7a637364761f8710891c"}, + {file = "scipy-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:392e4ec766654852c25ebad4f64e4e584cf19820b980bc04960bca0b0cd6eaa2"}, + {file = "scipy-1.13.1.tar.gz", hash = "sha256:095a87a0312b08dfd6a6155cbbd310a8c51800fc931b8c0b84003014b874ed3c"}, +] + +[package.dependencies] +numpy = ">=1.22.4,<2.3" + +[package.extras] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] +doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.12.0)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] +test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + +[[package]] +name = "scipy" +version = "1.16.1" +description = "Fundamental algorithms for scientific computing in Python" +optional = false +python-versions = ">=3.11" +groups = ["main"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "scipy-1.16.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:c033fa32bab91dc98ca59d0cf23bb876454e2bb02cbe592d5023138778f70030"}, + {file = "scipy-1.16.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:6e5c2f74e5df33479b5cd4e97a9104c511518fbd979aa9b8f6aec18b2e9ecae7"}, + {file = "scipy-1.16.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:0a55ffe0ba0f59666e90951971a884d1ff6f4ec3275a48f472cfb64175570f77"}, + {file = "scipy-1.16.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:f8a5d6cd147acecc2603fbd382fed6c46f474cccfcf69ea32582e033fb54dcfe"}, + {file = "scipy-1.16.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb18899127278058bcc09e7b9966d41a5a43740b5bb8dcba401bd983f82e885b"}, + {file = "scipy-1.16.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adccd93a2fa937a27aae826d33e3bfa5edf9aa672376a4852d23a7cd67a2e5b7"}, + {file = "scipy-1.16.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:18aca1646a29ee9a0625a1be5637fa798d4d81fdf426481f06d69af828f16958"}, + {file = "scipy-1.16.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d85495cef541729a70cdddbbf3e6b903421bc1af3e8e3a9a72a06751f33b7c39"}, + {file = "scipy-1.16.1-cp311-cp311-win_amd64.whl", hash = "sha256:226652fca853008119c03a8ce71ffe1b3f6d2844cc1686e8f9806edafae68596"}, + {file = "scipy-1.16.1-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:81b433bbeaf35728dad619afc002db9b189e45eebe2cd676effe1fb93fef2b9c"}, + {file = "scipy-1.16.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:886cc81fdb4c6903a3bb0464047c25a6d1016fef77bb97949817d0c0d79f9e04"}, + {file = "scipy-1.16.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:15240c3aac087a522b4eaedb09f0ad061753c5eebf1ea430859e5bf8640d5919"}, + {file = "scipy-1.16.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:65f81a25805f3659b48126b5053d9e823d3215e4a63730b5e1671852a1705921"}, + {file = "scipy-1.16.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6c62eea7f607f122069b9bad3f99489ddca1a5173bef8a0c75555d7488b6f725"}, + {file = "scipy-1.16.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f965bbf3235b01c776115ab18f092a95aa74c271a52577bcb0563e85738fd618"}, + {file = "scipy-1.16.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f006e323874ffd0b0b816d8c6a8e7f9a73d55ab3b8c3f72b752b226d0e3ac83d"}, + {file = "scipy-1.16.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8fd15fc5085ab4cca74cb91fe0a4263b1f32e4420761ddae531ad60934c2119"}, + {file = "scipy-1.16.1-cp312-cp312-win_amd64.whl", hash = "sha256:f7b8013c6c066609577d910d1a2a077021727af07b6fab0ee22c2f901f22352a"}, + {file = "scipy-1.16.1-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:5451606823a5e73dfa621a89948096c6528e2896e40b39248295d3a0138d594f"}, + {file = "scipy-1.16.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:89728678c5ca5abd610aee148c199ac1afb16e19844401ca97d43dc548a354eb"}, + {file = "scipy-1.16.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e756d688cb03fd07de0fffad475649b03cb89bee696c98ce508b17c11a03f95c"}, + {file = "scipy-1.16.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5aa2687b9935da3ed89c5dbed5234576589dd28d0bf7cd237501ccfbdf1ad608"}, + {file = "scipy-1.16.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0851f6a1e537fe9399f35986897e395a1aa61c574b178c0d456be5b1a0f5ca1f"}, + {file = "scipy-1.16.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fedc2cbd1baed37474b1924c331b97bdff611d762c196fac1a9b71e67b813b1b"}, + {file = "scipy-1.16.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2ef500e72f9623a6735769e4b93e9dcb158d40752cdbb077f305487e3e2d1f45"}, + {file = "scipy-1.16.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:978d8311674b05a8f7ff2ea6c6bce5d8b45a0cb09d4c5793e0318f448613ea65"}, + {file = "scipy-1.16.1-cp313-cp313-win_amd64.whl", hash = "sha256:81929ed0fa7a5713fcdd8b2e6f73697d3b4c4816d090dd34ff937c20fa90e8ab"}, + {file = "scipy-1.16.1-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:bcc12db731858abda693cecdb3bdc9e6d4bd200213f49d224fe22df82687bdd6"}, + {file = "scipy-1.16.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:744d977daa4becb9fc59135e75c069f8d301a87d64f88f1e602a9ecf51e77b27"}, + {file = "scipy-1.16.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:dc54f76ac18073bcecffb98d93f03ed6b81a92ef91b5d3b135dcc81d55a724c7"}, + {file = "scipy-1.16.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:367d567ee9fc1e9e2047d31f39d9d6a7a04e0710c86e701e053f237d14a9b4f6"}, + {file = "scipy-1.16.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4cf5785e44e19dcd32a0e4807555e1e9a9b8d475c6afff3d21c3c543a6aa84f4"}, + {file = "scipy-1.16.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3d0b80fb26d3e13a794c71d4b837e2a589d839fd574a6bbb4ee1288c213ad4a3"}, + {file = "scipy-1.16.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8503517c44c18d1030d666cb70aaac1cc8913608816e06742498833b128488b7"}, + {file = "scipy-1.16.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:30cc4bb81c41831ecfd6dc450baf48ffd80ef5aed0f5cf3ea775740e80f16ecc"}, + {file = "scipy-1.16.1-cp313-cp313t-win_amd64.whl", hash = "sha256:c24fa02f7ed23ae514460a22c57eca8f530dbfa50b1cfdbf4f37c05b5309cc39"}, + {file = "scipy-1.16.1-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:796a5a9ad36fa3a782375db8f4241ab02a091308eb079746bc0f874c9b998318"}, + {file = "scipy-1.16.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:3ea0733a2ff73fd6fdc5fecca54ee9b459f4d74f00b99aced7d9a3adb43fb1cc"}, + {file = "scipy-1.16.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:85764fb15a2ad994e708258bb4ed8290d1305c62a4e1ef07c414356a24fcfbf8"}, + {file = "scipy-1.16.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:ca66d980469cb623b1759bdd6e9fd97d4e33a9fad5b33771ced24d0cb24df67e"}, + {file = "scipy-1.16.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e7cc1ffcc230f568549fc56670bcf3df1884c30bd652c5da8138199c8c76dae0"}, + {file = "scipy-1.16.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3ddfb1e8d0b540cb4ee9c53fc3dea3186f97711248fb94b4142a1b27178d8b4b"}, + {file = "scipy-1.16.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4dc0e7be79e95d8ba3435d193e0d8ce372f47f774cffd882f88ea4e1e1ddc731"}, + {file = "scipy-1.16.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f23634f9e5adb51b2a77766dac217063e764337fbc816aa8ad9aaebcd4397fd3"}, + {file = "scipy-1.16.1-cp314-cp314-win_amd64.whl", hash = "sha256:57d75524cb1c5a374958a2eae3d84e1929bb971204cc9d52213fb8589183fc19"}, + {file = "scipy-1.16.1-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:d8da7c3dd67bcd93f15618938f43ed0995982eb38973023d46d4646c4283ad65"}, + {file = "scipy-1.16.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:cc1d2f2fd48ba1e0620554fe5bc44d3e8f5d4185c8c109c7fbdf5af2792cfad2"}, + {file = "scipy-1.16.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:21a611ced9275cb861bacadbada0b8c0623bc00b05b09eb97f23b370fc2ae56d"}, + {file = "scipy-1.16.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:8dfbb25dffc4c3dd9371d8ab456ca81beeaf6f9e1c2119f179392f0dc1ab7695"}, + {file = "scipy-1.16.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f0ebb7204f063fad87fc0a0e4ff4a2ff40b2a226e4ba1b7e34bf4b79bf97cd86"}, + {file = "scipy-1.16.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f1b9e5962656f2734c2b285a8745358ecb4e4efbadd00208c80a389227ec61ff"}, + {file = "scipy-1.16.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e1a106f8c023d57a2a903e771228bf5c5b27b5d692088f457acacd3b54511e4"}, + {file = "scipy-1.16.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:709559a1db68a9abc3b2c8672c4badf1614f3b440b3ab326d86a5c0491eafae3"}, + {file = "scipy-1.16.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c0c804d60492a0aad7f5b2bb1862f4548b990049e27e828391ff2bf6f7199998"}, + {file = "scipy-1.16.1.tar.gz", hash = "sha256:44c76f9e8b6e8e488a586190ab38016e4ed2f8a038af7cd3defa903c0a2238b3"}, +] + +[package.dependencies] +numpy = ">=1.25.2,<2.6" + +[package.extras] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] +doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "linkify-it-py", "matplotlib (>=3.5)", "myst-nb (>=1.2.0)", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.2.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] +test = ["Cython", "array-api-strict (>=2.3.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + +[[package]] +name = "seaborn" +version = "0.13.2" +description = "Statistical data visualization" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987"}, + {file = "seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7"}, +] + +[package.dependencies] +matplotlib = ">=3.4,<3.6.1 || >3.6.1" +numpy = ">=1.20,<1.24.0 || >1.24.0" +pandas = ">=1.2" + +[package.extras] +dev = ["flake8", "flit", "mypy", "pandas-stubs", "pre-commit", "pytest", "pytest-cov", "pytest-xdist"] +docs = ["ipykernel", "nbconvert", "numpydoc", "pydata_sphinx_theme (==0.10.0rc2)", "pyyaml", "sphinx (<6.0.0)", "sphinx-copybutton", "sphinx-design", "sphinx-issues"] +stats = ["scipy (>=1.7)", "statsmodels (>=0.12)"] + +[[package]] +name = "sentry-sdk" +version = "2.35.2" +description = "Python client for Sentry (https://sentry.io)" +optional = false +python-versions = ">=3.6" +groups = ["benchmarks"] +files = [ + {file = "sentry_sdk-2.35.2-py2.py3-none-any.whl", hash = "sha256:38c98e3cbb620dd3dd80a8d6e39c753d453dd41f8a9df581b0584c19a52bc926"}, + {file = "sentry_sdk-2.35.2.tar.gz", hash = "sha256:e9e8f3c795044beb59f2c8f4c6b9b0f9779e5e604099882df05eec525e782cc6"}, +] + +[package.dependencies] +certifi = "*" +urllib3 = ">=1.26.11" + +[package.extras] +aiohttp = ["aiohttp (>=3.5)"] +anthropic = ["anthropic (>=0.16)"] +arq = ["arq (>=0.23)"] +asyncpg = ["asyncpg (>=0.23)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +celery-redbeat = ["celery-redbeat (>=2)"] +chalice = ["chalice (>=1.16.0)"] +clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] +grpcio = ["grpcio (>=1.21.1)", "protobuf (>=3.8.0)"] +http2 = ["httpcore[http2] (==1.*)"] +httpx = ["httpx (>=0.16.0)"] +huey = ["huey (>=2)"] +huggingface-hub = ["huggingface_hub (>=0.22)"] +langchain = ["langchain (>=0.0.210)"] +launchdarkly = ["launchdarkly-server-sdk (>=9.8.0)"] +litestar = ["litestar (>=2.0.0)"] +loguru = ["loguru (>=0.5)"] +openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] +openfeature = ["openfeature-sdk (>=0.7.1)"] +opentelemetry = ["opentelemetry-distro (>=0.35b0)"] +opentelemetry-experimental = ["opentelemetry-distro"] +pure-eval = ["asttokens", "executing", "pure_eval"] +pymongo = ["pymongo (>=3.1)"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +starlite = ["starlite (>=1.48)"] +statsig = ["statsig (>=0.55.3)"] +tornado = ["tornado (>=6)"] +unleash = ["UnleashClient (>=6.0.1)"] + +[[package]] +name = "setuptools" +version = "80.9.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "(platform_machine == \"x86_64\" or python_version >= \"3.12\") and (platform_system == \"Linux\" or python_version >= \"3.12\")" +files = [ + {file = "setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"}, + {file = "setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\"", "ruff (>=0.8.0) ; sys_platform != \"cygwin\""] +core = ["importlib_metadata (>=6) ; python_version < \"3.10\"", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1) ; python_version < \"3.11\"", "wheel (>=0.43.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21) ; python_version >= \"3.9\" and sys_platform != \"cygwin\"", "jaraco.envs (>=2.2)", "jaraco.path (>=3.7.2)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf ; sys_platform != \"cygwin\"", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2) ; python_version < \"3.10\"", "jaraco.develop (>=7.21) ; sys_platform != \"cygwin\"", "mypy (==1.14.*)", "pytest-mypy"] + +[[package]] +name = "six" +version = "1.17.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["main"] +files = [ + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, +] + +[[package]] +name = "smmap" +version = "5.0.2" +description = "A pure Python implementation of a sliding window memory map manager" +optional = false +python-versions = ">=3.7" +groups = ["benchmarks"] +files = [ + {file = "smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e"}, + {file = "smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5"}, +] + +[[package]] +name = "snowballstemmer" +version = "3.0.1" +description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*" +groups = ["docs"] +files = [ + {file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"}, + {file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"}, +] + +[[package]] +name = "sphinx" +version = "7.4.7" +description = "Python documentation generator" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +markers = "python_version < \"3.11\"" +files = [ + {file = "sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239"}, + {file = "sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe"}, +] + +[package.dependencies] +alabaster = ">=0.7.14,<0.8.0" +babel = ">=2.13" +colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} +docutils = ">=0.20,<0.22" +imagesize = ">=1.3" +importlib-metadata = {version = ">=6.0", markers = "python_version < \"3.10\""} +Jinja2 = ">=3.1" +packaging = ">=23.0" +Pygments = ">=2.17" +requests = ">=2.30.0" +snowballstemmer = ">=2.2" +sphinxcontrib-applehelp = "*" +sphinxcontrib-devhelp = "*" +sphinxcontrib-htmlhelp = ">=2.0.0" +sphinxcontrib-jsmath = "*" +sphinxcontrib-qthelp = "*" +sphinxcontrib-serializinghtml = ">=1.1.9" +tomli = {version = ">=2", markers = "python_version < \"3.11\""} + +[package.extras] +docs = ["sphinxcontrib-websupport"] +lint = ["flake8 (>=6.0)", "importlib-metadata (>=6.0)", "mypy (==1.10.1)", "pytest (>=6.0)", "ruff (==0.5.2)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-docutils (==0.21.0.20240711)", "types-requests (>=2.30.0)"] +test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] + +[[package]] +name = "sphinx" +version = "8.2.3" +description = "Python documentation generator" +optional = false +python-versions = ">=3.11" +groups = ["docs"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3"}, + {file = "sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348"}, +] + +[package.dependencies] +alabaster = ">=0.7.14" +babel = ">=2.13" +colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} +docutils = ">=0.20,<0.22" +imagesize = ">=1.3" +Jinja2 = ">=3.1" +packaging = ">=23.0" +Pygments = ">=2.17" +requests = ">=2.30.0" +roman-numerals-py = ">=1.0.0" +snowballstemmer = ">=2.2" +sphinxcontrib-applehelp = ">=1.0.7" +sphinxcontrib-devhelp = ">=1.0.6" +sphinxcontrib-htmlhelp = ">=2.0.6" +sphinxcontrib-jsmath = ">=1.0.1" +sphinxcontrib-qthelp = ">=1.0.6" +sphinxcontrib-serializinghtml = ">=1.1.9" + +[package.extras] +docs = ["sphinxcontrib-websupport"] +lint = ["betterproto (==2.0.0b6)", "mypy (==1.15.0)", "pypi-attestations (==0.0.21)", "pyright (==1.1.395)", "pytest (>=8.0)", "ruff (==0.9.9)", "sphinx-lint (>=0.9)", "types-Pillow (==10.2.0.20240822)", "types-Pygments (==2.19.0.20250219)", "types-colorama (==0.4.15.20240311)", "types-defusedxml (==0.7.0.20240218)", "types-docutils (==0.21.0.20241128)", "types-requests (==2.32.0.20241016)", "types-urllib3 (==1.26.25.14)"] +test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "pytest-xdist[psutil] (>=3.4)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] + +[[package]] +name = "sphinx-rtd-theme" +version = "3.0.2" +description = "Read the Docs theme for Sphinx" +optional = false +python-versions = ">=3.8" +groups = ["docs"] +files = [ + {file = "sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13"}, + {file = "sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85"}, +] + +[package.dependencies] +docutils = ">0.18,<0.22" +sphinx = ">=6,<9" +sphinxcontrib-jquery = ">=4,<5" + +[package.extras] +dev = ["bump2version", "transifex-client", "twine", "wheel"] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, + {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, +] + +[package.extras] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, + {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, +] + +[package.extras] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, + {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, +] + +[package.extras] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] +test = ["html5lib", "pytest"] + +[[package]] +name = "sphinxcontrib-jquery" +version = "4.1" +description = "Extension to include jQuery on newer Sphinx releases" +optional = false +python-versions = ">=2.7" +groups = ["docs"] +files = [ + {file = "sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a"}, + {file = "sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"}, +] + +[package.dependencies] +Sphinx = ">=1.8" + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +description = "A sphinx extension which renders display math in HTML via JavaScript" +optional = false +python-versions = ">=3.5" +groups = ["docs"] +files = [ + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] + +[package.extras] +test = ["flake8", "mypy", "pytest"] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, + {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, +] + +[package.extras] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] +test = ["defusedxml (>=0.7.1)", "pytest"] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" +optional = false +python-versions = ">=3.9" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, + {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, +] + +[package.extras] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] +test = ["pytest"] + +[[package]] +name = "stevedore" +version = "5.5.0" +description = "Manage dynamic plugins for Python applications" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "stevedore-5.5.0-py3-none-any.whl", hash = "sha256:18363d4d268181e8e8452e71a38cd77630f345b2ef6b4a8d5614dac5ee0d18cf"}, + {file = "stevedore-5.5.0.tar.gz", hash = "sha256:d31496a4f4df9825e1a1e4f1f74d19abb0154aff311c3b376fcc89dae8fccd73"}, +] + +[[package]] +name = "sympy" +version = "1.14.0" +description = "Computer algebra system (CAS) in Python" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5"}, + {file = "sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517"}, +] + +[package.dependencies] +mpmath = ">=1.1.0,<1.4" + +[package.extras] +dev = ["hypothesis (>=6.70.0)", "pytest (>=7.1.0)"] + +[[package]] +name = "threadpoolctl" +version = "3.6.0" +description = "threadpoolctl" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb"}, + {file = "threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e"}, +] + +[[package]] +name = "tokenize-rt" +version = "6.2.0" +description = "A wrapper around the stdlib `tokenize` which roundtrips." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "tokenize_rt-6.2.0-py2.py3-none-any.whl", hash = "sha256:a152bf4f249c847a66497a4a95f63376ed68ac6abf092a2f7cfb29d044ecff44"}, + {file = "tokenize_rt-6.2.0.tar.gz", hash = "sha256:8439c042b330c553fdbe1758e4a05c0ed460dbbbb24a606f11f0dee75da4cad6"}, +] + +[[package]] +name = "tokenizers" +version = "0.22.0" +description = "" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "tokenizers-0.22.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:eaa9620122a3fb99b943f864af95ed14c8dfc0f47afa3b404ac8c16b3f2bb484"}, + {file = "tokenizers-0.22.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:71784b9ab5bf0ff3075bceeb198149d2c5e068549c0d18fe32d06ba0deb63f79"}, + {file = "tokenizers-0.22.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec5b71f668a8076802b0241a42387d48289f25435b86b769ae1837cad4172a17"}, + {file = "tokenizers-0.22.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ea8562fa7498850d02a16178105b58803ea825b50dc9094d60549a7ed63654bb"}, + {file = "tokenizers-0.22.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4136e1558a9ef2e2f1de1555dcd573e1cbc4a320c1a06c4107a3d46dc8ac6e4b"}, + {file = "tokenizers-0.22.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf5954de3962a5fd9781dc12048d24a1a6f1f5df038c6e95db328cd22964206"}, + {file = "tokenizers-0.22.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8337ca75d0731fc4860e6204cc24bb36a67d9736142aa06ed320943b50b1e7ed"}, + {file = "tokenizers-0.22.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a89264e26f63c449d8cded9061adea7b5de53ba2346fc7e87311f7e4117c1cc8"}, + {file = "tokenizers-0.22.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:790bad50a1b59d4c21592f9c3cf5e5cf9c3c7ce7e1a23a739f13e01fb1be377a"}, + {file = "tokenizers-0.22.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:76cf6757c73a10ef10bf06fa937c0ec7393d90432f543f49adc8cab3fb6f26cb"}, + {file = "tokenizers-0.22.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:1626cb186e143720c62c6c6b5371e62bbc10af60481388c0da89bc903f37ea0c"}, + {file = "tokenizers-0.22.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:da589a61cbfea18ae267723d6b029b84598dc8ca78db9951d8f5beff72d8507c"}, + {file = "tokenizers-0.22.0-cp39-abi3-win32.whl", hash = "sha256:dbf9d6851bddae3e046fedfb166f47743c1c7bd11c640f0691dd35ef0bcad3be"}, + {file = "tokenizers-0.22.0-cp39-abi3-win_amd64.whl", hash = "sha256:c78174859eeaee96021f248a56c801e36bfb6bd5b067f2e95aa82445ca324f00"}, + {file = "tokenizers-0.22.0.tar.gz", hash = "sha256:2e33b98525be8453f355927f3cab312c36cd3e44f4d7e9e97da2fa94d0a49dcb"}, +] + +[package.dependencies] +huggingface-hub = ">=0.16.4,<1.0" + +[package.extras] +dev = ["tokenizers[testing]"] +docs = ["setuptools-rust", "sphinx", "sphinx-rtd-theme"] +testing = ["black (==22.3)", "datasets", "numpy", "pytest", "pytest-asyncio", "requests", "ruff"] + +[[package]] +name = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +groups = ["dev", "docs"] +markers = "python_version < \"3.11\"" +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, +] + +[[package]] +name = "tomlkit" +version = "0.13.3" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0"}, + {file = "tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1"}, +] + +[[package]] +name = "torch" +version = "2.7.1" +description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" +optional = false +python-versions = ">=3.9.0" +groups = ["main"] +markers = "python_version >= \"3.12\"" +files = [ + {file = "torch-2.7.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a103b5d782af5bd119b81dbcc7ffc6fa09904c423ff8db397a1e6ea8fd71508f"}, + {file = "torch-2.7.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:fe955951bdf32d182ee8ead6c3186ad54781492bf03d547d31771a01b3d6fb7d"}, + {file = "torch-2.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:885453d6fba67d9991132143bf7fa06b79b24352f4506fd4d10b309f53454162"}, + {file = "torch-2.7.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:d72acfdb86cee2a32c0ce0101606f3758f0d8bb5f8f31e7920dc2809e963aa7c"}, + {file = "torch-2.7.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:236f501f2e383f1cb861337bdf057712182f910f10aeaf509065d54d339e49b2"}, + {file = "torch-2.7.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:06eea61f859436622e78dd0cdd51dbc8f8c6d76917a9cf0555a333f9eac31ec1"}, + {file = "torch-2.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:8273145a2e0a3c6f9fd2ac36762d6ee89c26d430e612b95a99885df083b04e52"}, + {file = "torch-2.7.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:aea4fc1bf433d12843eb2c6b2204861f43d8364597697074c8d38ae2507f8730"}, + {file = "torch-2.7.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:27ea1e518df4c9de73af7e8a720770f3628e7f667280bce2be7a16292697e3fa"}, + {file = "torch-2.7.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c33360cfc2edd976c2633b3b66c769bdcbbf0e0b6550606d188431c81e7dd1fc"}, + {file = "torch-2.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:d8bf6e1856ddd1807e79dc57e54d3335f2b62e6f316ed13ed3ecfe1fc1df3d8b"}, + {file = "torch-2.7.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:787687087412c4bd68d315e39bc1223f08aae1d16a9e9771d95eabbb04ae98fb"}, + {file = "torch-2.7.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:03563603d931e70722dce0e11999d53aa80a375a3d78e6b39b9f6805ea0a8d28"}, + {file = "torch-2.7.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:d632f5417b6980f61404a125b999ca6ebd0b8b4bbdbb5fbbba44374ab619a412"}, + {file = "torch-2.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:23660443e13995ee93e3d844786701ea4ca69f337027b05182f5ba053ce43b38"}, + {file = "torch-2.7.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:0da4f4dba9f65d0d203794e619fe7ca3247a55ffdcbd17ae8fb83c8b2dc9b585"}, + {file = "torch-2.7.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:e08d7e6f21a617fe38eeb46dd2213ded43f27c072e9165dc27300c9ef9570934"}, + {file = "torch-2.7.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:30207f672328a42df4f2174b8f426f354b2baa0b7cca3a0adb3d6ab5daf00dc8"}, + {file = "torch-2.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:79042feca1c634aaf6603fe6feea8c6b30dfa140a6bbc0b973e2260c7e79a22e"}, + {file = "torch-2.7.1-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:988b0cbc4333618a1056d2ebad9eb10089637b659eb645434d0809d8d937b946"}, + {file = "torch-2.7.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:e0d81e9a12764b6f3879a866607c8ae93113cbcad57ce01ebde63eb48a576369"}, + {file = "torch-2.7.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:8394833c44484547ed4a47162318337b88c97acdb3273d85ea06e03ffff44998"}, + {file = "torch-2.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:df41989d9300e6e3c19ec9f56f856187a6ef060c3662fe54f4b6baf1fc90bd19"}, + {file = "torch-2.7.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:a737b5edd1c44a5c1ece2e9f3d00df9d1b3fb9541138bee56d83d38293fb6c9d"}, +] + +[package.dependencies] +filelock = "*" +fsspec = "*" +jinja2 = "*" +networkx = "*" +nvidia-cublas-cu12 = {version = "12.6.4.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-cupti-cu12 = {version = "12.6.80", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-nvrtc-cu12 = {version = "12.6.77", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-runtime-cu12 = {version = "12.6.77", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cudnn-cu12 = {version = "9.5.1.17", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cufft-cu12 = {version = "11.3.0.4", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cufile-cu12 = {version = "1.11.1.6", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-curand-cu12 = {version = "10.3.7.77", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusolver-cu12 = {version = "11.7.1.2", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparse-cu12 = {version = "12.5.4.2", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparselt-cu12 = {version = "0.6.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nccl-cu12 = {version = "2.26.2", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvjitlink-cu12 = {version = "12.6.85", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvtx-cu12 = {version = "12.6.77", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +setuptools = {version = "*", markers = "python_version >= \"3.12\""} +sympy = ">=1.13.3" +triton = {version = "3.3.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +typing-extensions = ">=4.10.0" + +[package.extras] +opt-einsum = ["opt-einsum (>=3.3)"] +optree = ["optree (>=0.13.0)"] + +[[package]] +name = "torch" +version = "2.8.0" +description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" +optional = false +python-versions = ">=3.9.0" +groups = ["main"] +markers = "python_version <= \"3.11\"" +files = [ + {file = "torch-2.8.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:0be92c08b44009d4131d1ff7a8060d10bafdb7ddcb7359ef8d8c5169007ea905"}, + {file = "torch-2.8.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:89aa9ee820bb39d4d72b794345cccef106b574508dd17dbec457949678c76011"}, + {file = "torch-2.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e8e5bf982e87e2b59d932769938b698858c64cc53753894be25629bdf5cf2f46"}, + {file = "torch-2.8.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:a3f16a58a9a800f589b26d47ee15aca3acf065546137fc2af039876135f4c760"}, + {file = "torch-2.8.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:220a06fd7af8b653c35d359dfe1aaf32f65aa85befa342629f716acb134b9710"}, + {file = "torch-2.8.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:c12fa219f51a933d5f80eeb3a7a5d0cbe9168c0a14bbb4055f1979431660879b"}, + {file = "torch-2.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:8c7ef765e27551b2fbfc0f41bcf270e1292d9bf79f8e0724848b1682be6e80aa"}, + {file = "torch-2.8.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:5ae0524688fb6707c57a530c2325e13bb0090b745ba7b4a2cd6a3ce262572916"}, + {file = "torch-2.8.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e2fab4153768d433f8ed9279c8133a114a034a61e77a3a104dcdf54388838705"}, + {file = "torch-2.8.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2aca0939fb7e4d842561febbd4ffda67a8e958ff725c1c27e244e85e982173c"}, + {file = "torch-2.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:2f4ac52f0130275d7517b03a33d2493bab3693c83dcfadf4f81688ea82147d2e"}, + {file = "torch-2.8.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:619c2869db3ada2c0105487ba21b5008defcc472d23f8b80ed91ac4a380283b0"}, + {file = "torch-2.8.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2b2f96814e0345f5a5aed9bf9734efa913678ed19caf6dc2cddb7930672d6128"}, + {file = "torch-2.8.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:65616ca8ec6f43245e1f5f296603e33923f4c30f93d65e103d9e50c25b35150b"}, + {file = "torch-2.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:659df54119ae03e83a800addc125856effda88b016dfc54d9f65215c3975be16"}, + {file = "torch-2.8.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:1a62a1ec4b0498930e2543535cf70b1bef8c777713de7ceb84cd79115f553767"}, + {file = "torch-2.8.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:83c13411a26fac3d101fe8035a6b0476ae606deb8688e904e796a3534c197def"}, + {file = "torch-2.8.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:8f0a9d617a66509ded240add3754e462430a6c1fc5589f86c17b433dd808f97a"}, + {file = "torch-2.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:a7242b86f42be98ac674b88a4988643b9bc6145437ec8f048fea23f72feb5eca"}, + {file = "torch-2.8.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:7b677e17f5a3e69fdef7eb3b9da72622f8d322692930297e4ccb52fefc6c8211"}, + {file = "torch-2.8.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:da6afa31c13b669d4ba49d8a2169f0db2c3ec6bec4af898aa714f401d4c38904"}, + {file = "torch-2.8.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:06fcee8000e5c62a9f3e52a688b9c5abb7c6228d0e56e3452983416025c41381"}, + {file = "torch-2.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:5128fe752a355d9308e56af1ad28b15266fe2da5948660fad44de9e3a9e36e8c"}, + {file = "torch-2.8.0-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:e9f071f5b52a9f6970dc8a919694b27a91ae9dc08898b2b988abbef5eddfd1ae"}, +] + +[package.dependencies] +filelock = "*" +fsspec = "*" +jinja2 = "*" +networkx = "*" +nvidia-cublas-cu12 = {version = "12.8.4.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-cupti-cu12 = {version = "12.8.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-nvrtc-cu12 = {version = "12.8.93", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-runtime-cu12 = {version = "12.8.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cudnn-cu12 = {version = "9.10.2.21", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cufft-cu12 = {version = "11.3.3.83", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cufile-cu12 = {version = "1.13.1.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-curand-cu12 = {version = "10.3.9.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusolver-cu12 = {version = "11.7.3.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparse-cu12 = {version = "12.5.8.93", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparselt-cu12 = {version = "0.7.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nccl-cu12 = {version = "2.27.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvjitlink-cu12 = {version = "12.8.93", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvtx-cu12 = {version = "12.8.90", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +sympy = ">=1.13.3" +triton = {version = "3.4.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +typing-extensions = ">=4.10.0" + +[package.extras] +opt-einsum = ["opt-einsum (>=3.3)"] +optree = ["optree (>=0.13.0)"] +pyyaml = ["pyyaml"] + +[[package]] +name = "tqdm" +version = "4.67.1" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +groups = ["main", "benchmarks"] +files = [ + {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"}, + {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"] +discord = ["requests"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[[package]] +name = "transformers" +version = "4.56.0" +description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow" +optional = false +python-versions = ">=3.9.0" +groups = ["main"] +files = [ + {file = "transformers-4.56.0-py3-none-any.whl", hash = "sha256:bacf539c38dd850690856881c4974321af93a22f2ee96bcc994741a2121d8e71"}, + {file = "transformers-4.56.0.tar.gz", hash = "sha256:6ca9c3f38aa4da93ebf877db7156368c1c188c7465f09dbe70951e7622e987fa"}, +] + +[package.dependencies] +filelock = "*" +huggingface-hub = ">=0.34.0,<1.0" +numpy = ">=1.17" +packaging = ">=20.0" +pyyaml = ">=5.1" +regex = "!=2019.12.17" +requests = "*" +safetensors = ">=0.4.3" +tokenizers = ">=0.22.0,<=0.23.0" +tqdm = ">=4.27" + +[package.extras] +accelerate = ["accelerate (>=0.26.0)"] +all = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "av", "codecarbon (>=2.8.1)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "jinja2 (>=3.1.0)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "kernels (>=0.6.1,<=0.9)", "librosa", "mistral-common[opencv] (>=1.6.3)", "num2words", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm (!=1.0.18,<=1.0.19)", "tokenizers (>=0.22.0,<=0.23.0)", "torch (>=2.2)", "torchaudio", "torchvision"] +audio = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] +benchmark = ["optimum-benchmark (>=0.3.0)"] +chat-template = ["jinja2 (>=3.1.0)"] +codecarbon = ["codecarbon (>=2.8.1)"] +deepspeed = ["accelerate (>=0.26.0)", "deepspeed (>=0.9.3)"] +deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.26.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "deepspeed (>=0.9.3)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "libcst", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "optuna", "parameterized (>=0.9)", "protobuf", "psutil", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.11.2)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "timeout-decorator"] +dev = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "av", "beautifulsoup4", "codecarbon (>=2.8.1)", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "jinja2 (>=3.1.0)", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "kernels (>=0.6.1,<=0.9)", "libcst", "librosa", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "num2words", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "pandas (<2.3.0)", "parameterized (>=0.9)", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.11.2)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "timm (!=1.0.18,<=1.0.19)", "tokenizers (>=0.22.0,<=0.23.0)", "torch (>=2.2)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +dev-tensorflow = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "kenlm", "keras-nlp (>=0.3.1,<0.14.0)", "libcst", "librosa", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "pandas (<2.3.0)", "parameterized (>=0.9)", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures", "pytest-rich", "pytest-timeout", "pytest-xdist", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.11.2)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "tokenizers (>=0.22.0,<=0.23.0)", "urllib3 (<2.0.0)"] +dev-torch = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.26.0)", "beautifulsoup4", "codecarbon (>=2.8.1)", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "kenlm", "kernels (>=0.6.1,<=0.9)", "libcst", "librosa", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "num2words", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "pandas (<2.3.0)", "parameterized (>=0.9)", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rich", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.11.2)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "timeout-decorator", "timm (!=1.0.18,<=1.0.19)", "tokenizers (>=0.22.0,<=0.23.0)", "torch (>=2.2)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +flax = ["flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "optax (>=0.0.8,<=0.1.4)", "scipy (<1.13.0)"] +flax-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] +ftfy = ["ftfy"] +hf-xet = ["hf-xet"] +hub-kernels = ["kernels (>=0.6.1,<=0.9)"] +integrations = ["kernels (>=0.6.1,<=0.9)", "optuna", "ray[tune] (>=2.7.0)", "sigopt"] +ja = ["fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "rhoknp (>=1.1.0,<1.3.1)", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)"] +mistral-common = ["mistral-common[opencv] (>=1.6.3)"] +modelcreation = ["cookiecutter (==1.7.3)"] +natten = ["natten (>=0.14.6,<0.15.0)"] +num2words = ["num2words"] +onnx = ["onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "tf2onnx"] +onnxruntime = ["onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)"] +open-telemetry = ["opentelemetry-api", "opentelemetry-exporter-otlp", "opentelemetry-sdk"] +optuna = ["optuna"] +quality = ["GitPython (<3.1.19)", "datasets (>=2.15.0)", "libcst", "pandas (<2.3.0)", "rich", "ruff (==0.11.2)", "urllib3 (<2.0.0)"] +ray = ["ray[tune] (>=2.7.0)"] +retrieval = ["datasets (>=2.15.0)", "faiss-cpu"] +ruff = ["ruff (==0.11.2)"] +sagemaker = ["sagemaker (>=2.31.0)"] +sentencepiece = ["protobuf", "sentencepiece (>=0.1.91,!=0.1.92)"] +serving = ["accelerate (>=0.26.0)", "fastapi", "openai (>=1.98.0)", "pydantic (>=2)", "starlette", "torch (>=2.2)", "uvicorn"] +sigopt = ["sigopt"] +sklearn = ["scikit-learn"] +speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] +testing = ["GitPython (<3.1.19)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (>=2.15.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "libcst", "mistral-common[opencv] (>=1.6.3)", "nltk (<=3.8.1)", "parameterized (>=0.9)", "psutil", "pydantic (>=2)", "pytest (>=7.2.0)", "pytest-asyncio", "pytest-order", "pytest-rerunfailures", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.11.2)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "timeout-decorator"] +tf = ["keras-nlp (>=0.3.1,<0.14.0)", "onnxconverter-common", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx"] +tf-cpu = ["keras (>2.9,<2.16)", "keras-nlp (>=0.3.1,<0.14.0)", "onnxconverter-common", "tensorflow-cpu (>2.9,<2.16)", "tensorflow-probability (<0.24)", "tensorflow-text (<2.16)", "tf2onnx"] +tf-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] +tiktoken = ["blobfile", "tiktoken"] +timm = ["timm (!=1.0.18,<=1.0.19)"] +tokenizers = ["tokenizers (>=0.22.0,<=0.23.0)"] +torch = ["accelerate (>=0.26.0)", "torch (>=2.2)"] +torch-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] +torch-vision = ["Pillow (>=10.0.1,<=15.0)", "torchvision"] +torchhub = ["filelock", "huggingface-hub (>=0.34.0,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.22.0,<=0.23.0)", "torch (>=2.2)", "tqdm (>=4.27)"] +video = ["av"] +vision = ["Pillow (>=10.0.1,<=15.0)"] + +[[package]] +name = "triton" +version = "3.3.1" +description = "A language and compiler for custom Deep Learning operations" +optional = false +python-versions = "*" +groups = ["main"] +markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version >= \"3.12\"" +files = [ + {file = "triton-3.3.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b74db445b1c562844d3cfad6e9679c72e93fdfb1a90a24052b03bb5c49d1242e"}, + {file = "triton-3.3.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b31e3aa26f8cb3cc5bf4e187bf737cbacf17311e1112b781d4a059353dfd731b"}, + {file = "triton-3.3.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9999e83aba21e1a78c1f36f21bce621b77bcaa530277a50484a7cb4a822f6e43"}, + {file = "triton-3.3.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b89d846b5a4198317fec27a5d3a609ea96b6d557ff44b56c23176546023c4240"}, + {file = "triton-3.3.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3198adb9d78b77818a5388bff89fa72ff36f9da0bc689db2f0a651a67ce6a42"}, + {file = "triton-3.3.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f6139aeb04a146b0b8e0fbbd89ad1e65861c57cfed881f21d62d3cb94a36bab7"}, +] + +[package.dependencies] +setuptools = ">=40.8.0" + +[package.extras] +build = ["cmake (>=3.20)", "lit"] +tests = ["autopep8", "isort", "llnl-hatchet", "numpy", "pytest", "pytest-forked", "pytest-xdist", "scipy (>=1.7.1)"] +tutorials = ["matplotlib", "pandas", "tabulate"] + +[[package]] +name = "triton" +version = "3.4.0" +description = "A language and compiler for custom Deep Learning operations" +optional = false +python-versions = "<3.14,>=3.9" +groups = ["main"] +markers = "platform_machine == \"x86_64\" and platform_system == \"Linux\" and python_version <= \"3.11\"" +files = [ + {file = "triton-3.4.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ff2785de9bc02f500e085420273bb5cc9c9bb767584a4aa28d6e360cec70128"}, + {file = "triton-3.4.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b70f5e6a41e52e48cfc087436c8a28c17ff98db369447bcaff3b887a3ab4467"}, + {file = "triton-3.4.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31c1d84a5c0ec2c0f8e8a072d7fd150cab84a9c239eaddc6706c081bfae4eb04"}, + {file = "triton-3.4.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00be2964616f4c619193cb0d1b29a99bd4b001d7dc333816073f92cf2a8ccdeb"}, + {file = "triton-3.4.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7936b18a3499ed62059414d7df563e6c163c5e16c3773678a3ee3d417865035d"}, + {file = "triton-3.4.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98e5c1442eaeabae2e2452ae765801bd53cd4ce873cab0d1bdd59a32ab2d9397"}, +] + +[package.dependencies] +importlib-metadata = {version = "*", markers = "python_version < \"3.10\""} +setuptools = ">=40.8.0" + +[package.extras] +build = ["cmake (>=3.20,<4.0)", "lit"] +tests = ["autopep8", "isort", "llnl-hatchet", "numpy", "pytest", "pytest-forked", "pytest-xdist", "scipy (>=1.7.1)"] +tutorials = ["matplotlib", "pandas", "tabulate"] + +[[package]] +name = "types-pyyaml" +version = "6.0.12.20250822" +description = "Typing stubs for PyYAML" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "types_pyyaml-6.0.12.20250822-py3-none-any.whl", hash = "sha256:1fe1a5e146aa315483592d292b72a172b65b946a6d98aa6ddd8e4aa838ab7098"}, + {file = "types_pyyaml-6.0.12.20250822.tar.gz", hash = "sha256:259f1d93079d335730a9db7cff2bcaf65d7e04b4a56b5927d49a612199b59413"}, +] + +[[package]] +name = "types-requests" +version = "2.32.4.20250809" +description = "Typing stubs for requests" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "types_requests-2.32.4.20250809-py3-none-any.whl", hash = "sha256:f73d1832fb519ece02c85b1f09d5f0dd3108938e7d47e7f94bbfa18a6782b163"}, + {file = "types_requests-2.32.4.20250809.tar.gz", hash = "sha256:d8060de1c8ee599311f56ff58010fb4902f462a1470802cf9f6ed27bc46c4df3"}, +] + +[package.dependencies] +urllib3 = ">=2" + +[[package]] +name = "types-setuptools" +version = "80.9.0.20250822" +description = "Typing stubs for setuptools" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "types_setuptools-80.9.0.20250822-py3-none-any.whl", hash = "sha256:53bf881cb9d7e46ed12c76ef76c0aaf28cfe6211d3fab12e0b83620b1a8642c3"}, + {file = "types_setuptools-80.9.0.20250822.tar.gz", hash = "sha256:070ea7716968ec67a84c7f7768d9952ff24d28b65b6594797a464f1b3066f965"}, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" +optional = false +python-versions = ">=3.9" +groups = ["main", "benchmarks", "dev"] +files = [ + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +groups = ["benchmarks"] +files = [ + {file = "typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51"}, + {file = "typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"}, +] + +[package.dependencies] +typing-extensions = ">=4.12.0" + +[[package]] +name = "tzdata" +version = "2025.2" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +groups = ["main"] +files = [ + {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, + {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, +] + +[[package]] +name = "untokenize" +version = "0.1.1" +description = "Transforms tokens into original source code (while preserving whitespace)." +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "untokenize-0.1.1.tar.gz", hash = "sha256:3865dbbbb8efb4bb5eaa72f1be7f3e0be00ea8b7f125c69cbd1f5fda926f37a2"}, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.9" +groups = ["main", "benchmarks", "dev", "docs"] +files = [ + {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, + {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "virtualenv" +version = "20.34.0" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "virtualenv-20.34.0-py3-none-any.whl", hash = "sha256:341f5afa7eee943e4984a9207c025feedd768baff6753cd660c857ceb3e36026"}, + {file = "virtualenv-20.34.0.tar.gz", hash = "sha256:44815b2c9dee7ed86e387b842a84f20b93f7f417f95886ca1996a72a4138eb1a"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" +typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\""} + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] + +[[package]] +name = "wandb" +version = "0.21.3" +description = "A CLI and library for interacting with the Weights & Biases API." +optional = false +python-versions = ">=3.8" +groups = ["benchmarks"] +files = [ + {file = "wandb-0.21.3-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:f85bac45b4482742ec9ff190af38eb00a877ddeb4875475e7e487dc19300ff03"}, + {file = "wandb-0.21.3-py3-none-macosx_12_0_arm64.whl", hash = "sha256:8a2b3ba419b91d47edead2755f04cef54f9e3c4496ee0c9854c3cfeff4216dd3"}, + {file = "wandb-0.21.3-py3-none-macosx_12_0_x86_64.whl", hash = "sha256:35a1972881f3b85755befab004118234593792a9f05e07fd6345780172f4420e"}, + {file = "wandb-0.21.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d9cf8588cb090a2a41f589037fda72c57c9e23edfbd2ad829e575f1305d942c"}, + {file = "wandb-0.21.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff24b6b8e0f9da840b6bd5c7f60b0a5507bd998db40c9c2d476f9a340bec8ed"}, + {file = "wandb-0.21.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4975dec19e2b343e23ed6e60f7e1290120553719f82e87a22205bede758416ad"}, + {file = "wandb-0.21.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:514a0aad40ecc0bdb757b1dc86e4ac98f61d2d760445b6e1f555291562320f2d"}, + {file = "wandb-0.21.3-py3-none-win32.whl", hash = "sha256:45aa3d8ad53c6ee06f37490d7a329ed7d0f5ca4dbd5d05bb0c01d5da22f14691"}, + {file = "wandb-0.21.3-py3-none-win_amd64.whl", hash = "sha256:56d5a5697766f552a9933d8c6a564202194768eb0389bd5f9fe9a99cd4cee41e"}, + {file = "wandb-0.21.3.tar.gz", hash = "sha256:031e24e2aad0ce735dfdcc74baf2f2c12c106f500ed24798de6ef9b9e63bb432"}, +] + +[package.dependencies] +click = ">=8.0.1" +eval-type-backport = {version = "*", markers = "python_version < \"3.10\""} +gitpython = ">=1.0.0,<3.1.29 || >3.1.29" +packaging = "*" +platformdirs = "*" +protobuf = [ + {version = ">=3.15.0,<4.21.0 || >4.21.0,<5.28.0 || >5.28.0,<7", markers = "python_version == \"3.9\" and sys_platform == \"linux\""}, + {version = ">=3.19.0,<4.21.0 || >4.21.0,<5.28.0 || >5.28.0,<7", markers = "python_version > \"3.9\" or sys_platform != \"linux\""}, +] +pydantic = "<3" +pyyaml = "*" +requests = ">=2.0.0,<3" +sentry-sdk = ">=2.0.0" +typing-extensions = ">=4.8,<5" + +[package.extras] +aws = ["boto3", "botocore (>=1.5.76)"] +azure = ["azure-identity", "azure-storage-blob"] +gcp = ["google-cloud-storage"] +importers = ["filelock", "mlflow", "polars (<=1.2.1)", "rich", "tenacity"] +kubeflow = ["google-cloud-storage", "kubernetes", "minio", "sh"] +launch = ["awscli", "azure-containerregistry", "azure-identity", "azure-storage-blob", "boto3", "botocore (>=1.5.76)", "chardet", "google-auth", "google-cloud-aiplatform", "google-cloud-artifact-registry", "google-cloud-compute", "google-cloud-storage", "iso8601", "jsonschema", "kubernetes", "kubernetes-asyncio", "nbconvert", "nbformat", "optuna", "pydantic", "pyyaml (>=6.0.0)", "tomli", "tornado (>=6.5.0) ; python_version >= \"3.9\"", "typing-extensions"] +media = ["bokeh", "imageio (>=2.28.1)", "moviepy (>=1.0.0)", "numpy", "pillow", "plotly (>=5.18.0)", "rdkit", "soundfile"] +models = ["cloudpickle"] +perf = ["orjson"] +sweeps = ["sweeps (>=0.2.0)"] +workspaces = ["wandb-workspaces"] + +[[package]] +name = "wrapt" +version = "1.17.3" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04"}, + {file = "wrapt-1.17.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2"}, + {file = "wrapt-1.17.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd341868a4b6714a5962c1af0bd44f7c404ef78720c7de4892901e540417111c"}, + {file = "wrapt-1.17.3-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f9b2601381be482f70e5d1051a5965c25fb3625455a2bf520b5a077b22afb775"}, + {file = "wrapt-1.17.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:343e44b2a8e60e06a7e0d29c1671a0d9951f59174f3709962b5143f60a2a98bd"}, + {file = "wrapt-1.17.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:33486899acd2d7d3066156b03465b949da3fd41a5da6e394ec49d271baefcf05"}, + {file = "wrapt-1.17.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e6f40a8aa5a92f150bdb3e1c44b7e98fb7113955b2e5394122fa5532fec4b418"}, + {file = "wrapt-1.17.3-cp310-cp310-win32.whl", hash = "sha256:a36692b8491d30a8c75f1dfee65bef119d6f39ea84ee04d9f9311f83c5ad9390"}, + {file = "wrapt-1.17.3-cp310-cp310-win_amd64.whl", hash = "sha256:afd964fd43b10c12213574db492cb8f73b2f0826c8df07a68288f8f19af2ebe6"}, + {file = "wrapt-1.17.3-cp310-cp310-win_arm64.whl", hash = "sha256:af338aa93554be859173c39c85243970dc6a289fa907402289eeae7543e1ae18"}, + {file = "wrapt-1.17.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7"}, + {file = "wrapt-1.17.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85"}, + {file = "wrapt-1.17.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f"}, + {file = "wrapt-1.17.3-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311"}, + {file = "wrapt-1.17.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1"}, + {file = "wrapt-1.17.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5"}, + {file = "wrapt-1.17.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2"}, + {file = "wrapt-1.17.3-cp311-cp311-win32.whl", hash = "sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89"}, + {file = "wrapt-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77"}, + {file = "wrapt-1.17.3-cp311-cp311-win_arm64.whl", hash = "sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a"}, + {file = "wrapt-1.17.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0"}, + {file = "wrapt-1.17.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba"}, + {file = "wrapt-1.17.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd"}, + {file = "wrapt-1.17.3-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828"}, + {file = "wrapt-1.17.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9"}, + {file = "wrapt-1.17.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396"}, + {file = "wrapt-1.17.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc"}, + {file = "wrapt-1.17.3-cp312-cp312-win32.whl", hash = "sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe"}, + {file = "wrapt-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c"}, + {file = "wrapt-1.17.3-cp312-cp312-win_arm64.whl", hash = "sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6"}, + {file = "wrapt-1.17.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0"}, + {file = "wrapt-1.17.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77"}, + {file = "wrapt-1.17.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7"}, + {file = "wrapt-1.17.3-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277"}, + {file = "wrapt-1.17.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d"}, + {file = "wrapt-1.17.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa"}, + {file = "wrapt-1.17.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050"}, + {file = "wrapt-1.17.3-cp313-cp313-win32.whl", hash = "sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8"}, + {file = "wrapt-1.17.3-cp313-cp313-win_amd64.whl", hash = "sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb"}, + {file = "wrapt-1.17.3-cp313-cp313-win_arm64.whl", hash = "sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16"}, + {file = "wrapt-1.17.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39"}, + {file = "wrapt-1.17.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235"}, + {file = "wrapt-1.17.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c"}, + {file = "wrapt-1.17.3-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b"}, + {file = "wrapt-1.17.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa"}, + {file = "wrapt-1.17.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7"}, + {file = "wrapt-1.17.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4"}, + {file = "wrapt-1.17.3-cp314-cp314-win32.whl", hash = "sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10"}, + {file = "wrapt-1.17.3-cp314-cp314-win_amd64.whl", hash = "sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6"}, + {file = "wrapt-1.17.3-cp314-cp314-win_arm64.whl", hash = "sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58"}, + {file = "wrapt-1.17.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a"}, + {file = "wrapt-1.17.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067"}, + {file = "wrapt-1.17.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454"}, + {file = "wrapt-1.17.3-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e"}, + {file = "wrapt-1.17.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f"}, + {file = "wrapt-1.17.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056"}, + {file = "wrapt-1.17.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804"}, + {file = "wrapt-1.17.3-cp314-cp314t-win32.whl", hash = "sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977"}, + {file = "wrapt-1.17.3-cp314-cp314t-win_amd64.whl", hash = "sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116"}, + {file = "wrapt-1.17.3-cp314-cp314t-win_arm64.whl", hash = "sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6"}, + {file = "wrapt-1.17.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:70d86fa5197b8947a2fa70260b48e400bf2ccacdcab97bb7de47e3d1e6312225"}, + {file = "wrapt-1.17.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:df7d30371a2accfe4013e90445f6388c570f103d61019b6b7c57e0265250072a"}, + {file = "wrapt-1.17.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:caea3e9c79d5f0d2c6d9ab96111601797ea5da8e6d0723f77eabb0d4068d2b2f"}, + {file = "wrapt-1.17.3-cp38-cp38-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:758895b01d546812d1f42204bd443b8c433c44d090248bf22689df673ccafe00"}, + {file = "wrapt-1.17.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02b551d101f31694fc785e58e0720ef7d9a10c4e62c1c9358ce6f63f23e30a56"}, + {file = "wrapt-1.17.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:656873859b3b50eeebe6db8b1455e99d90c26ab058db8e427046dbc35c3140a5"}, + {file = "wrapt-1.17.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a9a2203361a6e6404f80b99234fe7fb37d1fc73487b5a78dc1aa5b97201e0f22"}, + {file = "wrapt-1.17.3-cp38-cp38-win32.whl", hash = "sha256:55cbbc356c2842f39bcc553cf695932e8b30e30e797f961860afb308e6b1bb7c"}, + {file = "wrapt-1.17.3-cp38-cp38-win_amd64.whl", hash = "sha256:ad85e269fe54d506b240d2d7b9f5f2057c2aa9a2ea5b32c66f8902f768117ed2"}, + {file = "wrapt-1.17.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:30ce38e66630599e1193798285706903110d4f057aab3168a34b7fdc85569afc"}, + {file = "wrapt-1.17.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:65d1d00fbfb3ea5f20add88bbc0f815150dbbde3b026e6c24759466c8b5a9ef9"}, + {file = "wrapt-1.17.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7c06742645f914f26c7f1fa47b8bc4c91d222f76ee20116c43d5ef0912bba2d"}, + {file = "wrapt-1.17.3-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7e18f01b0c3e4a07fe6dfdb00e29049ba17eadbc5e7609a2a3a4af83ab7d710a"}, + {file = "wrapt-1.17.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f5f51a6466667a5a356e6381d362d259125b57f059103dd9fdc8c0cf1d14139"}, + {file = "wrapt-1.17.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:59923aa12d0157f6b82d686c3fd8e1166fa8cdfb3e17b42ce3b6147ff81528df"}, + {file = "wrapt-1.17.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:46acc57b331e0b3bcb3e1ca3b421d65637915cfcd65eb783cb2f78a511193f9b"}, + {file = "wrapt-1.17.3-cp39-cp39-win32.whl", hash = "sha256:3e62d15d3cfa26e3d0788094de7b64efa75f3a53875cdbccdf78547aed547a81"}, + {file = "wrapt-1.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:1f23fa283f51c890eda8e34e4937079114c74b4c81d2b2f1f1d94948f5cc3d7f"}, + {file = "wrapt-1.17.3-cp39-cp39-win_arm64.whl", hash = "sha256:24c2ed34dc222ed754247a2702b1e1e89fdbaa4016f324b4b8f1a802d4ffe87f"}, + {file = "wrapt-1.17.3-py3-none-any.whl", hash = "sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22"}, + {file = "wrapt-1.17.3.tar.gz", hash = "sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0"}, +] + +[[package]] +name = "xxhash" +version = "3.5.0" +description = "Python binding for xxHash" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "xxhash-3.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ece616532c499ee9afbb83078b1b952beffef121d989841f7f4b3dc5ac0fd212"}, + {file = "xxhash-3.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3171f693dbc2cef6477054a665dc255d996646b4023fe56cb4db80e26f4cc520"}, + {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c5d3e570ef46adaf93fc81b44aca6002b5a4d8ca11bd0580c07eac537f36680"}, + {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cb29a034301e2982df8b1fe6328a84f4b676106a13e9135a0d7e0c3e9f806da"}, + {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d0d307d27099bb0cbeea7260eb39ed4fdb99c5542e21e94bb6fd29e49c57a23"}, + {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0342aafd421795d740e514bc9858ebddfc705a75a8c5046ac56d85fe97bf196"}, + {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dbbd9892c5ebffeca1ed620cf0ade13eb55a0d8c84e0751a6653adc6ac40d0c"}, + {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4cc2d67fdb4d057730c75a64c5923abfa17775ae234a71b0200346bfb0a7f482"}, + {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ec28adb204b759306a3d64358a5e5c07d7b1dd0ccbce04aa76cb9377b7b70296"}, + {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1328f6d8cca2b86acb14104e381225a3d7b42c92c4b86ceae814e5c400dbb415"}, + {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8d47ebd9f5d9607fd039c1fbf4994e3b071ea23eff42f4ecef246ab2b7334198"}, + {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b96d559e0fcddd3343c510a0fe2b127fbff16bf346dd76280b82292567523442"}, + {file = "xxhash-3.5.0-cp310-cp310-win32.whl", hash = "sha256:61c722ed8d49ac9bc26c7071eeaa1f6ff24053d553146d5df031802deffd03da"}, + {file = "xxhash-3.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:9bed5144c6923cc902cd14bb8963f2d5e034def4486ab0bbe1f58f03f042f9a9"}, + {file = "xxhash-3.5.0-cp310-cp310-win_arm64.whl", hash = "sha256:893074d651cf25c1cc14e3bea4fceefd67f2921b1bb8e40fcfeba56820de80c6"}, + {file = "xxhash-3.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02c2e816896dc6f85922ced60097bcf6f008dedfc5073dcba32f9c8dd786f3c1"}, + {file = "xxhash-3.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6027dcd885e21581e46d3c7f682cfb2b870942feeed58a21c29583512c3f09f8"}, + {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1308fa542bbdbf2fa85e9e66b1077eea3a88bef38ee8a06270b4298a7a62a166"}, + {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c28b2fdcee797e1c1961cd3bcd3d545cab22ad202c846235197935e1df2f8ef7"}, + {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:924361811732ddad75ff23e90efd9ccfda4f664132feecb90895bade6a1b4623"}, + {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89997aa1c4b6a5b1e5b588979d1da048a3c6f15e55c11d117a56b75c84531f5a"}, + {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:685c4f4e8c59837de103344eb1c8a3851f670309eb5c361f746805c5471b8c88"}, + {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbd2ecfbfee70bc1a4acb7461fa6af7748ec2ab08ac0fa298f281c51518f982c"}, + {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:25b5a51dc3dfb20a10833c8eee25903fd2e14059e9afcd329c9da20609a307b2"}, + {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a8fb786fb754ef6ff8c120cb96629fb518f8eb5a61a16aac3a979a9dbd40a084"}, + {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a905ad00ad1e1c34fe4e9d7c1d949ab09c6fa90c919860c1534ff479f40fd12d"}, + {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:963be41bcd49f53af6d795f65c0da9b4cc518c0dd9c47145c98f61cb464f4839"}, + {file = "xxhash-3.5.0-cp311-cp311-win32.whl", hash = "sha256:109b436096d0a2dd039c355fa3414160ec4d843dfecc64a14077332a00aeb7da"}, + {file = "xxhash-3.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:b702f806693201ad6c0a05ddbbe4c8f359626d0b3305f766077d51388a6bac58"}, + {file = "xxhash-3.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:c4dcb4120d0cc3cc448624147dba64e9021b278c63e34a38789b688fd0da9bf3"}, + {file = "xxhash-3.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:14470ace8bd3b5d51318782cd94e6f94431974f16cb3b8dc15d52f3b69df8e00"}, + {file = "xxhash-3.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59aa1203de1cb96dbeab595ded0ad0c0056bb2245ae11fac11c0ceea861382b9"}, + {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08424f6648526076e28fae6ea2806c0a7d504b9ef05ae61d196d571e5c879c84"}, + {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61a1ff00674879725b194695e17f23d3248998b843eb5e933007ca743310f793"}, + {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2f2c61bee5844d41c3eb015ac652a0229e901074951ae48581d58bfb2ba01be"}, + {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d32a592cac88d18cc09a89172e1c32d7f2a6e516c3dfde1b9adb90ab5df54a6"}, + {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70dabf941dede727cca579e8c205e61121afc9b28516752fd65724be1355cc90"}, + {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e5d0ddaca65ecca9c10dcf01730165fd858533d0be84c75c327487c37a906a27"}, + {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e5b5e16c5a480fe5f59f56c30abdeba09ffd75da8d13f6b9b6fd224d0b4d0a2"}, + {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149b7914451eb154b3dfaa721315117ea1dac2cc55a01bfbd4df7c68c5dd683d"}, + {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:eade977f5c96c677035ff39c56ac74d851b1cca7d607ab3d8f23c6b859379cab"}, + {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa9f547bd98f5553d03160967866a71056a60960be00356a15ecc44efb40ba8e"}, + {file = "xxhash-3.5.0-cp312-cp312-win32.whl", hash = "sha256:f7b58d1fd3551b8c80a971199543379be1cee3d0d409e1f6d8b01c1a2eebf1f8"}, + {file = "xxhash-3.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:fa0cafd3a2af231b4e113fba24a65d7922af91aeb23774a8b78228e6cd785e3e"}, + {file = "xxhash-3.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:586886c7e89cb9828bcd8a5686b12e161368e0064d040e225e72607b43858ba2"}, + {file = "xxhash-3.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:37889a0d13b0b7d739cfc128b1c902f04e32de17b33d74b637ad42f1c55101f6"}, + {file = "xxhash-3.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:97a662338797c660178e682f3bc180277b9569a59abfb5925e8620fba00b9fc5"}, + {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f85e0108d51092bdda90672476c7d909c04ada6923c14ff9d913c4f7dc8a3bc"}, + {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2fd827b0ba763ac919440042302315c564fdb797294d86e8cdd4578e3bc7f3"}, + {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:82085c2abec437abebf457c1d12fccb30cc8b3774a0814872511f0f0562c768c"}, + {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07fda5de378626e502b42b311b049848c2ef38784d0d67b6f30bb5008642f8eb"}, + {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c279f0d2b34ef15f922b77966640ade58b4ccdfef1c4d94b20f2a364617a493f"}, + {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:89e66ceed67b213dec5a773e2f7a9e8c58f64daeb38c7859d8815d2c89f39ad7"}, + {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bcd51708a633410737111e998ceb3b45d3dbc98c0931f743d9bb0a209033a326"}, + {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ff2c0a34eae7df88c868be53a8dd56fbdf592109e21d4bfa092a27b0bf4a7bf"}, + {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4e28503dccc7d32e0b9817aa0cbfc1f45f563b2c995b7a66c4c8a0d232e840c7"}, + {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a6c50017518329ed65a9e4829154626f008916d36295b6a3ba336e2458824c8c"}, + {file = "xxhash-3.5.0-cp313-cp313-win32.whl", hash = "sha256:53a068fe70301ec30d868ece566ac90d873e3bb059cf83c32e76012c889b8637"}, + {file = "xxhash-3.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:80babcc30e7a1a484eab952d76a4f4673ff601f54d5142c26826502740e70b43"}, + {file = "xxhash-3.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:4811336f1ce11cac89dcbd18f3a25c527c16311709a89313c3acaf771def2d4b"}, + {file = "xxhash-3.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6e5f70f6dca1d3b09bccb7daf4e087075ff776e3da9ac870f86ca316736bb4aa"}, + {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e76e83efc7b443052dd1e585a76201e40b3411fe3da7af4fe434ec51b2f163b"}, + {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33eac61d0796ca0591f94548dcfe37bb193671e0c9bcf065789b5792f2eda644"}, + {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ec70a89be933ea49222fafc3999987d7899fc676f688dd12252509434636622"}, + {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86b8e7f703ec6ff4f351cfdb9f428955859537125904aa8c963604f2e9d3e7"}, + {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0adfbd36003d9f86c8c97110039f7539b379f28656a04097e7434d3eaf9aa131"}, + {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:63107013578c8a730419adc05608756c3fa640bdc6abe806c3123a49fb829f43"}, + {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:683b94dbd1ca67557850b86423318a2e323511648f9f3f7b1840408a02b9a48c"}, + {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:5d2a01dcce81789cf4b12d478b5464632204f4c834dc2d064902ee27d2d1f0ee"}, + {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:a9d360a792cbcce2fe7b66b8d51274ec297c53cbc423401480e53b26161a290d"}, + {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:f0b48edbebea1b7421a9c687c304f7b44d0677c46498a046079d445454504737"}, + {file = "xxhash-3.5.0-cp37-cp37m-win32.whl", hash = "sha256:7ccb800c9418e438b44b060a32adeb8393764da7441eb52aa2aa195448935306"}, + {file = "xxhash-3.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c3bc7bf8cb8806f8d1c9bf149c18708cb1c406520097d6b0a73977460ea03602"}, + {file = "xxhash-3.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:74752ecaa544657d88b1d1c94ae68031e364a4d47005a90288f3bab3da3c970f"}, + {file = "xxhash-3.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dee1316133c9b463aa81aca676bc506d3f80d8f65aeb0bba2b78d0b30c51d7bd"}, + {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:602d339548d35a8579c6b013339fb34aee2df9b4e105f985443d2860e4d7ffaa"}, + {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:695735deeddfb35da1677dbc16a083445360e37ff46d8ac5c6fcd64917ff9ade"}, + {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1030a39ba01b0c519b1a82f80e8802630d16ab95dc3f2b2386a0b5c8ed5cbb10"}, + {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5bc08f33c4966f4eb6590d6ff3ceae76151ad744576b5fc6c4ba8edd459fdec"}, + {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160e0c19ee500482ddfb5d5570a0415f565d8ae2b3fd69c5dcfce8a58107b1c3"}, + {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f1abffa122452481a61c3551ab3c89d72238e279e517705b8b03847b1d93d738"}, + {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:d5e9db7ef3ecbfc0b4733579cea45713a76852b002cf605420b12ef3ef1ec148"}, + {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:23241ff6423378a731d84864bf923a41649dc67b144debd1077f02e6249a0d54"}, + {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:82b833d5563fefd6fceafb1aed2f3f3ebe19f84760fdd289f8b926731c2e6e91"}, + {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0a80ad0ffd78bef9509eee27b4a29e56f5414b87fb01a888353e3d5bda7038bd"}, + {file = "xxhash-3.5.0-cp38-cp38-win32.whl", hash = "sha256:50ac2184ffb1b999e11e27c7e3e70cc1139047e7ebc1aa95ed12f4269abe98d4"}, + {file = "xxhash-3.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:392f52ebbb932db566973693de48f15ce787cabd15cf6334e855ed22ea0be5b3"}, + {file = "xxhash-3.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfc8cdd7f33d57f0468b0614ae634cc38ab9202c6957a60e31d285a71ebe0301"}, + {file = "xxhash-3.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e0c48b6300cd0b0106bf49169c3e0536408dfbeb1ccb53180068a18b03c662ab"}, + {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe1a92cfbaa0a1253e339ccec42dbe6db262615e52df591b68726ab10338003f"}, + {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33513d6cc3ed3b559134fb307aae9bdd94d7e7c02907b37896a6c45ff9ce51bd"}, + {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eefc37f6138f522e771ac6db71a6d4838ec7933939676f3753eafd7d3f4c40bc"}, + {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a606c8070ada8aa2a88e181773fa1ef17ba65ce5dd168b9d08038e2a61b33754"}, + {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42eca420c8fa072cc1dd62597635d140e78e384a79bb4944f825fbef8bfeeef6"}, + {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:604253b2143e13218ff1ef0b59ce67f18b8bd1c4205d2ffda22b09b426386898"}, + {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6e93a5ad22f434d7876665444a97e713a8f60b5b1a3521e8df11b98309bff833"}, + {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:7a46e1d6d2817ba8024de44c4fd79913a90e5f7265434cef97026215b7d30df6"}, + {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:30eb2efe6503c379b7ab99c81ba4a779748e3830241f032ab46bd182bf5873af"}, + {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c8aa771ff2c13dd9cda8166d685d7333d389fae30a4d2bb39d63ab5775de8606"}, + {file = "xxhash-3.5.0-cp39-cp39-win32.whl", hash = "sha256:5ed9ebc46f24cf91034544b26b131241b699edbfc99ec5e7f8f3d02d6eb7fba4"}, + {file = "xxhash-3.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:220f3f896c6b8d0316f63f16c077d52c412619e475f9372333474ee15133a558"}, + {file = "xxhash-3.5.0-cp39-cp39-win_arm64.whl", hash = "sha256:a7b1d8315d9b5e9f89eb2933b73afae6ec9597a258d52190944437158b49d38e"}, + {file = "xxhash-3.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2014c5b3ff15e64feecb6b713af12093f75b7926049e26a580e94dcad3c73d8c"}, + {file = "xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fab81ef75003eda96239a23eda4e4543cedc22e34c373edcaf744e721a163986"}, + {file = "xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2febf914ace002132aa09169cc572e0d8959d0f305f93d5828c4836f9bc5a6"}, + {file = "xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d3a10609c51da2a1c0ea0293fc3968ca0a18bd73838455b5bca3069d7f8e32b"}, + {file = "xxhash-3.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5a74f23335b9689b66eb6dbe2a931a88fcd7a4c2cc4b1cb0edba8ce381c7a1da"}, + {file = "xxhash-3.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b4154c00eb22e4d543f472cfca430e7962a0f1d0f3778334f2e08a7ba59363c"}, + {file = "xxhash-3.5.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d30bbc1644f726b825b3278764240f449d75f1a8bdda892e641d4a688b1494ae"}, + {file = "xxhash-3.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fa0b72f2423e2aa53077e54a61c28e181d23effeaafd73fcb9c494e60930c8e"}, + {file = "xxhash-3.5.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13de2b76c1835399b2e419a296d5b38dc4855385d9e96916299170085ef72f57"}, + {file = "xxhash-3.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0691bfcc4f9c656bcb96cc5db94b4d75980b9d5589f2e59de790091028580837"}, + {file = "xxhash-3.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:297595fe6138d4da2c8ce9e72a04d73e58725bb60f3a19048bc96ab2ff31c692"}, + {file = "xxhash-3.5.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc1276d369452040cbb943300dc8abeedab14245ea44056a2943183822513a18"}, + {file = "xxhash-3.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2061188a1ba352fc699c82bff722f4baacb4b4b8b2f0c745d2001e56d0dfb514"}, + {file = "xxhash-3.5.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38c384c434021e4f62b8d9ba0bc9467e14d394893077e2c66d826243025e1f81"}, + {file = "xxhash-3.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e6a4dd644d72ab316b580a1c120b375890e4c52ec392d4aef3c63361ec4d77d1"}, + {file = "xxhash-3.5.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:531af8845aaadcadf951b7e0c1345c6b9c68a990eeb74ff9acd8501a0ad6a1c9"}, + {file = "xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ce379bcaa9fcc00f19affa7773084dd09f5b59947b3fb47a1ceb0179f91aaa1"}, + {file = "xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd1b2281d01723f076df3c8188f43f2472248a6b63118b036e641243656b1b0f"}, + {file = "xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c770750cc80e8694492244bca7251385188bc5597b6a39d98a9f30e8da984e0"}, + {file = "xxhash-3.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b150b8467852e1bd844387459aa6fbe11d7f38b56e901f9f3b3e6aba0d660240"}, + {file = "xxhash-3.5.0.tar.gz", hash = "sha256:84f2caddf951c9cbf8dc2e22a89d4ccf5d86391ac6418fe81e3c67d0cf60b45f"}, +] + +[[package]] +name = "yarl" +version = "1.20.1" +description = "Yet another URL library" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4"}, + {file = "yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a"}, + {file = "yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23"}, + {file = "yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24"}, + {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13"}, + {file = "yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8"}, + {file = "yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16"}, + {file = "yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e"}, + {file = "yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b"}, + {file = "yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8"}, + {file = "yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1"}, + {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e"}, + {file = "yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773"}, + {file = "yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e"}, + {file = "yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9"}, + {file = "yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a"}, + {file = "yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd"}, + {file = "yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a"}, + {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004"}, + {file = "yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5"}, + {file = "yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698"}, + {file = "yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a"}, + {file = "yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3"}, + {file = "yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5"}, + {file = "yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b"}, + {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1"}, + {file = "yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7"}, + {file = "yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c"}, + {file = "yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d"}, + {file = "yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf"}, + {file = "yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3"}, + {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458"}, + {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e"}, + {file = "yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d"}, + {file = "yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f"}, + {file = "yarl-1.20.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e42ba79e2efb6845ebab49c7bf20306c4edf74a0b20fc6b2ccdd1a219d12fad3"}, + {file = "yarl-1.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:41493b9b7c312ac448b7f0a42a089dffe1d6e6e981a2d76205801a023ed26a2b"}, + {file = "yarl-1.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f5a5928ff5eb13408c62a968ac90d43f8322fd56d87008b8f9dabf3c0f6ee983"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30c41ad5d717b3961b2dd785593b67d386b73feca30522048d37298fee981805"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:59febc3969b0781682b469d4aca1a5cab7505a4f7b85acf6db01fa500fa3f6ba"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2b6fb3622b7e5bf7a6e5b679a69326b4279e805ed1699d749739a61d242449e"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:749d73611db8d26a6281086f859ea7ec08f9c4c56cec864e52028c8b328db723"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9427925776096e664c39e131447aa20ec738bdd77c049c48ea5200db2237e000"}, + {file = "yarl-1.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff70f32aa316393eaf8222d518ce9118148eddb8a53073c2403863b41033eed5"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c7ddf7a09f38667aea38801da8b8d6bfe81df767d9dfc8c88eb45827b195cd1c"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:57edc88517d7fc62b174fcfb2e939fbc486a68315d648d7e74d07fac42cec240"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:dab096ce479d5894d62c26ff4f699ec9072269d514b4edd630a393223f45a0ee"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14a85f3bd2d7bb255be7183e5d7d6e70add151a98edf56a770d6140f5d5f4010"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c89b5c792685dd9cd3fa9761c1b9f46fc240c2a3265483acc1565769996a3f8"}, + {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:69e9b141de5511021942a6866990aea6d111c9042235de90e08f94cf972ca03d"}, + {file = "yarl-1.20.1-cp39-cp39-win32.whl", hash = "sha256:b5f307337819cdfdbb40193cad84978a029f847b0a357fbe49f712063cfc4f06"}, + {file = "yarl-1.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:eae7bfe2069f9c1c5b05fc7fe5d612e5bbc089a39309904ee8b829e322dcad00"}, + {file = "yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77"}, + {file = "yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" +propcache = ">=0.2.1" + +[[package]] +name = "zipp" +version = "3.23.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.9" +groups = ["main", "docs"] +markers = "python_version == \"3.9\"" +files = [ + {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, + {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, +] + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more_itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.9,<4.0" +content-hash = "5f7a95ad5122825bf0fb6ab75c9390a1f257b32404bea15bc611e07372ca33d9" diff --git a/pyproject.toml b/pyproject.toml index 3bcc130d..9b94b8b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,17 +1,18 @@ [build-system] -requires = ["setuptools>=61.0", "wheel"] -build-backend = "setuptools.build_meta" +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" -[project] +[tool.poetry] name = "sparse-attention-hub" version = "0.1.0" -description = "A comprehensive framework for sparse attention mechanisms" -authors = [ - {name = "AlexCuadron", email = "alex.cl.2000@gmail.com"} -] +description = "A framework for implementing and evaluating sparse attention mechanisms" +authors = ["Aditya Desai ", "AlexCuadron ", "Kumar Krishna Agrawal ", "Luis Gaspar Schroeder "] readme = "README.md" -license = {text = "MIT"} -requires-python = ">=3.9" +license = "MIT" +homepage = "https://github.com/xAlg-ai/sparse-attention-hub" +repository = "https://github.com/xAlg-ai/sparse-attention-hub" +documentation = "https://sparse-attention-hub.readthedocs.io" +keywords = ["attention", "sparse", "transformer", "deep-learning", "pytorch"] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", @@ -19,86 +20,75 @@ classifiers = [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Topic :: Scientific/Engineering :: Artificial Intelligence", "Topic :: Software Development :: Libraries :: Python Modules", ] -keywords = ["attention", "sparse", "transformer", "deep-learning", "pytorch"] +packages = [{include = "sparse_attention_hub"}] -dependencies = [ - "torch>=1.9.0", - "numpy>=1.21.0", - "matplotlib>=3.5.0", - "seaborn>=0.11.0", - "datasets>=2.0.0", - "transformers>=4.20.0", - "scikit-learn>=1.0.0", - "rouge>=1.0.0", - "nltk>=3.8.0", - "bert-score>=0.3.0", - "jieba>=0.42.0", - "hf-transfer>=0.1.9", - "fuzzywuzzy>=0.18.0", - "pip>=25.1.1", - "pytest>=8.4.1", - "psutil>=7.0.0", - "plotly>=6.2.0", - "pandas>=2.3.1", - "pynvml>=12.0.0", - "colorama>=0.4.6", -] +[tool.poetry.dependencies] +python = ">=3.9,<4.0" +torch = ">=1.9.0" +numpy = ">=1.21.0" +matplotlib = ">=3.5.0" +seaborn = ">=0.11.0" +datasets = ">=2.0.0" +transformers = ">=4.20.0" +scikit-learn = ">=1.0.0" +rouge = ">=1.0.0" +nltk = ">=3.8.0" +bert-score = ">=0.3.0" +jieba = ">=0.42.0" +hf-transfer = ">=0.1.9" +fuzzywuzzy = ">=0.18.0" +psutil = ">=7.0.0" +plotly = ">=6.2.0" +pandas = ">=2.3.1" +pynvml = ">=12.0.0" +colorama = ">=0.4.6" -[project.optional-dependencies] -dev = [ - # Testing - "pytest>=7.4.0", - "pytest-cov>=4.1.0", - "pytest-xdist>=3.3.1", - "pytest-mock>=3.11.1", - "mock>=5.2.0", - # Linting and formatting - "black==22.10.0", - "isort==5.12.0", - "flake8==5.0.4", - "pylint==2.17.4", - "mypy==1.4.0", - "bandit>=1.7.5", - "pyupgrade>=3.10.1", - "docformatter>=1.7.5", - # Pre-commit hooks - "pre-commit>=3.3.3", - # Type stubs - "types-PyYAML>=6.0.12.11", - "types-requests>=2.31.0.2", - "types-setuptools>=68.0.0.3", -] -docs = [ - "sphinx>=5.0.0", - "sphinx-rtd-theme>=1.0.0", - "myst-parser>=0.18.0", -] -benchmarks = [ - "wandb>=0.13.0", - "tqdm>=4.64.0", - "pandas>=1.5.0", -] +[tool.poetry.group.dev.dependencies] +# Testing +pytest = ">=7.4.0" +pytest-cov = ">=4.1.0" +pytest-xdist = ">=3.3.1" +pytest-mock = ">=3.11.1" +mock = ">=5.2.0" +# Linting and formatting +black = "22.10.0" +isort = "5.12.0" +flake8 = "5.0.4" +pylint = "2.17.4" +mypy = "1.4.0" +bandit = ">=1.7.5" +pyupgrade = ">=3.10.1" +docformatter = ">=1.7.5" +# Pre-commit hooks +pre-commit = ">=3.3.3" +# Type stubs +types-PyYAML = ">=6.0.12.11" +types-requests = ">=2.31.0.2" +types-setuptools = ">=68.0.0.3" -[project.urls] -Homepage = "https://github.com/xAlg-ai/sparse-attention-hub" -Repository = "https://github.com/xAlg-ai/sparse-attention-hub" -Documentation = "https://sparse-attention-hub.readthedocs.io" -"Bug Tracker" = "https://github.com/xAlg-ai/sparse-attention-hub/issues" +[tool.poetry.group.docs] +optional = true -[project.scripts] -sparse-attention-benchmark = "sparse_attention_hub.benchmark.executor:main" +[tool.poetry.group.docs.dependencies] +sphinx = ">=5.0.0" +sphinx-rtd-theme = ">=1.0.0" +myst-parser = ">=0.18.0" + +[tool.poetry.group.benchmarks] +optional = true -[tool.setuptools.packages.find] -where = ["."] -include = ["sparse_attention_hub*"] -exclude = ["tests*"] +[tool.poetry.group.benchmarks.dependencies] +wandb = ">=0.13.0" +tqdm = ">=4.64.0" + +[tool.poetry.scripts] +sparse-attention-benchmark = "sparse_attention_hub.benchmark.executor:main" [tool.pytest.ini_options] testpaths = ["tests"] @@ -120,7 +110,7 @@ markers = [ [tool.black] line-length = 88 -target-version = ["py38", "py39", "py310", "py311"] +target-version = ["py39", "py310", "py311"] include = '\.pyi?$' extend-exclude = ''' /( @@ -143,7 +133,7 @@ line_length = 88 known_first_party = ["sparse_attention_hub"] [tool.mypy] -python_version = "3.8" +python_version = "3.9" warn_return_any = true warn_unused_configs = true disallow_untyped_defs = true @@ -156,6 +146,7 @@ warn_unused_ignores = true warn_no_return = true warn_unreachable = true strict_equality = true + [[tool.mypy.overrides]] module = [ "torch.*", @@ -166,4 +157,4 @@ module = [ "wandb.*", ] ignore_missing_imports = true -ignore_errors = true +ignore_errors = true \ No newline at end of file diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 424422ea..00000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,38 +0,0 @@ -# Development dependencies for sparse-attention-hub -# Linting and formatting -black==22.10.0 -isort==5.12.0 -flake8==5.0.4 -pylint==2.17.4 -mypy==1.4.0 -bandit==1.7.5 -pyupgrade==3.10.1 -docformatter==1.7.5 - -# Testing -pytest==7.4.0 -pytest-cov==4.1.0 -pytest-xdist==3.3.1 -pytest-mock==3.11.1 -mock==5.2.0 - -# Pre-commit hooks -pre-commit==3.3.3 - -# Type stubs -types-PyYAML==6.0.12.11 -types-requests==2.31.0.2 -types-setuptools==68.0.0.3 - -# Documentation -sphinx==7.1.2 -sphinx-rtd-theme==1.3.0 -myst-parser==2.0.0 - -# Jupyter for examples -jupyter==1.0.0 -ipykernel==6.25.0 - -# Additional development tools -twine==4.0.2 -build==0.10.0 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 23116853..00000000 --- a/requirements.txt +++ /dev/null @@ -1,20 +0,0 @@ -# Core dependencies -torch>=1.9.0 -numpy>=1.21.0 -matplotlib>=3.5.0 -seaborn>=0.11.0 -datasets>=2.0.0 -transformers>=4.20.0 - -# Development dependencies -pytest>=7.0.0 -pytest-cov>=4.0.0 -black>=22.0.0 -isort>=5.10.0 -flake8>=5.0.0 -mypy>=0.991 - -# Optional dependencies for benchmarks -wandb>=0.13.0 -tqdm>=4.64.0 -pandas>=1.5.0 \ No newline at end of file diff --git a/scripts/format.sh b/scripts/format.sh index 7d3fdfd2..0fbd9c50 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -23,7 +23,7 @@ builtin cd "$ROOT" || exit 1 # Check if development dependencies are installed check_tool_installed() { if ! command -v "$1" &> /dev/null; then - echo "Error: $1 is not installed. Please run: pip install -r requirements-dev.txt" + echo "Error: $1 is not installed. Please run: poetry install --with dev" exit 1 fi } @@ -43,7 +43,7 @@ tool_version_check() { if [[ "$installed_version" != "$required_version" ]]; then echo "Warning: $tool_name version mismatch. Required: $required_version, Installed: $installed_version" - echo "Consider running: pip install -r requirements-dev.txt" + echo "Consider running: poetry install --with dev" fi } @@ -54,13 +54,13 @@ FLAKE8_VERSION=$(flake8 --version | head -n 1 | awk '{print $1}') MYPY_VERSION=$(mypy --version | awk '{print $2}') PYLINT_VERSION=$(pylint --version | head -n 1 | awk '{print $2}') -# Check versions against requirements-dev.txt -if [[ -f "requirements-dev.txt" ]]; then - tool_version_check "black" "$BLACK_VERSION" "$(grep "black==" requirements-dev.txt | cut -d'=' -f3)" - tool_version_check "isort" "$ISORT_VERSION" "$(grep "isort==" requirements-dev.txt | cut -d'=' -f3)" - tool_version_check "flake8" "$FLAKE8_VERSION" "$(grep "flake8==" requirements-dev.txt | cut -d'=' -f3)" - tool_version_check "mypy" "$MYPY_VERSION" "$(grep "mypy==" requirements-dev.txt | cut -d'=' -f3)" - tool_version_check "pylint" "$PYLINT_VERSION" "$(grep "pylint==" requirements-dev.txt | cut -d'=' -f3)" +# Check versions against pyproject.toml +if [[ -f "pyproject.toml" ]]; then + tool_version_check "black" "$BLACK_VERSION" "$(grep 'black = ' pyproject.toml | sed 's/.*"\(.*\)".*/\1/')" + tool_version_check "isort" "$ISORT_VERSION" "$(grep 'isort = ' pyproject.toml | sed 's/.*"\(.*\)".*/\1/')" + tool_version_check "flake8" "$FLAKE8_VERSION" "$(grep 'flake8 = ' pyproject.toml | sed 's/.*"\(.*\)".*/\1/')" + tool_version_check "mypy" "$MYPY_VERSION" "$(grep 'mypy = ' pyproject.toml | sed 's/.*"\(.*\)".*/\1/')" + tool_version_check "pylint" "$PYLINT_VERSION" "$(grep 'pylint = ' pyproject.toml | sed 's/.*"\(.*\)".*/\1/')" fi # Formatting flags diff --git a/scripts/lint.sh b/scripts/lint.sh index dba86cdf..0aa9e2af 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -29,7 +29,7 @@ NC='\033[0m' # No Color # Check if tool is installed check_tool() { if ! command -v "$1" &> /dev/null; then - echo -e "${RED}Error: $1 is not installed. Please run: pip install -r requirements-dev.txt${NC}" + echo -e "${RED}Error: $1 is not installed. Please run: poetry install --with dev${NC}" return 1 fi return 0 From fc3ffcf5f91ffbad45d2da72dc03522c864cb8e7 Mon Sep 17 00:00:00 2001 From: Luis Gaspar Schroeder Date: Wed, 3 Sep 2025 10:08:26 +0200 Subject: [PATCH 3/4] Improved architecture --- sparse_attention_hub/metric_logging/logger.py | 458 +++++++++++++----- sparse_attention_hub/plotting/generator.py | 283 +++++++---- .../efficient_attention/base.py | 67 ++- .../research_attention/base.py | 245 ++++++++-- .../utils/hashattention_utils.py | 380 +++++++++++---- 5 files changed, 1070 insertions(+), 363 deletions(-) diff --git a/sparse_attention_hub/metric_logging/logger.py b/sparse_attention_hub/metric_logging/logger.py index 8663135c..a42bc53b 100644 --- a/sparse_attention_hub/metric_logging/logger.py +++ b/sparse_attention_hub/metric_logging/logger.py @@ -13,23 +13,41 @@ @dataclass class LogEvent: - """Log event data structure.""" + """Log event data structure for metric logging. + + Attributes: + timestamp: When the event was logged. + metric: Metric identifier string. + value: The actual metric value (can be None). + metadata: Additional context information like layer, head, etc. + location: Auto-inferred location as "module.function" or "class.method". + """ timestamp: datetime - metric: str # Metric identifier string + metric: str value: Union[None, Any] - metadata: Dict[str, Any] # Additional context (layer, head, etc.) - location: str # Auto-inferred: "module.function" or "class.method" + metadata: Dict[str, Any] + location: str class MicroMetricLogger: - """Singleton logger for micro metrics with queue-based architecture.""" + """Singleton logger for micro metrics with queue-based architecture. + + This class provides a singleton pattern for logging micro metrics during + sparse attention operations. It supports metric registration, sampling, + and configurable limits on record count and flush behavior. + + Attributes: + log_path: Optional directory path where log files will be written. + flush_every: Number of events after which to flush to disk. + flush_interval: Time interval in seconds for automatic flushing. + max_records: Maximum number of records to log (None for unlimited). + sampling_factor: Probability of logging each event (0.0-1.0). + """ _instance: Optional["MicroMetricLogger"] = None _initialized: bool = False - - # Class-level storage for registered metrics (works without initialization) - _registered_metrics: Dict[str, type] = {} # identifier -> dtype mapping + _registered_metrics: Dict[str, type] = {} def __new__(cls, *args, **kwargs) -> "MicroMetricLogger": if cls._instance is None: @@ -39,46 +57,119 @@ def __new__(cls, *args, **kwargs) -> "MicroMetricLogger": def __init__( self, log_path: Optional[str] = None, - flush_every: int = 1000, # Flush every N events - flush_interval: float = 60.0, # Flush every N seconds - enabled_metrics: Union[List[str], str] = None, - max_records: Optional[int] = None, # Maximum number of events to log - sampling_factor: float = 1.0, # Probability of logging each event (0.0-1.0) - ): # List of string identifiers to enable, or "all" + flush_every: int = 1000, + flush_interval: float = 60.0, + enabled_metrics: Union[List[str], str, None] = None, + max_records: Optional[int] = None, + sampling_factor: float = 1.0, + ) -> None: + """Initialize the MicroMetricLogger. + + Args: + log_path: Optional directory path where log files will be written. + flush_every: Number of events after which to flush to disk. + flush_interval: Time interval in seconds for automatic flushing. + enabled_metrics: List of metric identifiers to enable, "all", or None. + max_records: Maximum number of events to log (None for unlimited). + sampling_factor: Probability of logging each event (0.0-1.0). + """ if not self._initialized: - self.log_path = log_path - self.flush_every = flush_every - self.flush_interval = flush_interval - self.max_records = max_records - self.sampling_factor = max( - 0.0, min(1.0, sampling_factor) - ) # Clamp to [0.0, 1.0] - - # Internal state - self.log_queue: deque = deque(maxlen=10000) # Circular buffer - self.enabled_metrics: set = set() - self.last_flush_time = time.time() - self._total_records_logged: int = 0 # Track total events logged - - # Enable metrics if log_path is provided - if self.log_path is not None: - self._ensure_log_directory() - self.enable_metrics(enabled_metrics) - - MicroMetricLogger._initialized = True + self._initialize_logger( + log_path, flush_every, flush_interval, + enabled_metrics, max_records, sampling_factor + ) else: - if self.log_path and log_path and self.log_path != log_path: - print( - f"Warning: MicroMetricLogger already initialized with log_path: {self.log_path}" - ) + self._handle_reinitialization(log_path) + + def _initialize_logger( + self, + log_path: Optional[str], + flush_every: int, + flush_interval: float, + enabled_metrics: Union[List[str], str, None], + max_records: Optional[int], + sampling_factor: float, + ) -> None: + """Initialize logger instance for the first time. + + Args: + log_path: Directory path for log files. + flush_every: Number of events before flushing. + flush_interval: Time interval for flushing. + enabled_metrics: Metrics to enable initially. + max_records: Maximum records limit. + sampling_factor: Event sampling probability. + """ + self._set_configuration(log_path, flush_every, flush_interval, max_records, sampling_factor) + self._initialize_state() + self._configure_logging_if_needed(log_path, enabled_metrics) + MicroMetricLogger._initialized = True + + def _set_configuration( + self, + log_path: Optional[str], + flush_every: int, + flush_interval: float, + max_records: Optional[int], + sampling_factor: float, + ) -> None: + """Set logger configuration parameters. + + Args: + log_path: Directory path for log files. + flush_every: Number of events before flushing. + flush_interval: Time interval for flushing. + max_records: Maximum records limit. + sampling_factor: Event sampling probability. + """ + self.log_path = log_path + self.flush_every = flush_every + self.flush_interval = flush_interval + self.max_records = max_records + self.sampling_factor = max(0.0, min(1.0, sampling_factor)) + + def _initialize_state(self) -> None: + """Initialize internal state variables.""" + self.log_queue: deque = deque(maxlen=10000) + self.enabled_metrics: set = set() + self.last_flush_time = time.time() + self._total_records_logged: int = 0 - # main registration function + def _configure_logging_if_needed( + self, + log_path: Optional[str], + enabled_metrics: Union[List[str], str, None] + ) -> None: + """Configure logging if log path is provided. + + Args: + log_path: Directory path for log files. + enabled_metrics: Metrics to enable initially. + """ + if log_path is not None: + self._ensure_log_directory() + self.enable_metrics(enabled_metrics) + + def _handle_reinitialization(self, log_path: Optional[str]) -> None: + """Handle warning when logger is reinitialized. + + Args: + log_path: New log path being requested. + """ + if self.log_path and log_path and self.log_path != log_path: + print( + f"Warning: MicroMetricLogger already initialized with log_path: {self.log_path}" + ) @classmethod def register_metric(cls, identifier: str, dtype: type) -> None: """Register a metric with its string identifier and expected data type. - This works at class level and doesn't require initialization. + This works at class level and doesn't require logger initialization. + + Args: + identifier: Unique string identifier for the metric. + dtype: Expected data type for the metric values. """ if identifier in cls._registered_metrics: print(f"Warning: Metric '{identifier}' is being re-registered") @@ -86,35 +177,33 @@ def register_metric(cls, identifier: str, dtype: type) -> None: @classmethod def get_registered_metrics(cls) -> Dict[str, type]: - """Get all registered metrics at class level.""" + """Get all registered metrics at class level. + + Returns: + Dictionary mapping metric identifiers to their expected data types. + """ return cls._registered_metrics.copy() - # helper methods - def _ensure_log_directory(self) -> None: """Ensure the log directory exists.""" if self.log_path is not None: os.makedirs(self.log_path, exist_ok=True) def _get_calling_location(self) -> str: - """Get the calling location using inspect module.""" + """Get the calling location using inspect module. + + Returns: + String representation of the calling location in format + "module.class.method" or "module.function". + """ try: - # Get the calling frame (skip this method and the log method) caller_frame = inspect.currentframe().f_back.f_back if caller_frame is None: return "unknown" - # Get module name - module = inspect.getmodule(caller_frame) - module_name = module.__name__ if module else "unknown" - - # Get function/class name + module_name = self._get_module_name(caller_frame) function_name = caller_frame.f_code.co_name - - # Try to get class name if it's a method - class_name = None - if "self" in caller_frame.f_locals: - class_name = caller_frame.f_locals["self"].__class__.__name__ + class_name = self._get_class_name(caller_frame) if class_name: return f"{module_name}.{class_name}.{function_name}" @@ -123,66 +212,147 @@ def _get_calling_location(self) -> str: except Exception: return "unknown" - def __del__(self): - """Cleanup when logger is destroyed.""" - self.flush() # Final flush + def _get_module_name(self, frame: Any) -> str: + """Get module name from frame. + + Args: + frame: Stack frame object. + + Returns: + Module name or "unknown" if not available. + """ + module = inspect.getmodule(frame) + return module.__name__ if module else "unknown" - # api + def _get_class_name(self, frame: Any) -> Optional[str]: + """Get class name from frame if it's a method call. + + Args: + frame: Stack frame object. + + Returns: + Class name if available, None otherwise. + """ + if "self" in frame.f_locals: + return frame.f_locals["self"].__class__.__name__ + return None - def enable_metrics(self, metrics: Union[List[str], str] = None) -> None: + def __del__(self) -> None: + """Cleanup when logger is destroyed.""" + self.flush() + + def enable_metrics(self, metrics: Union[List[str], str, None] = None) -> None: """Enable logging for specific metrics. Args: - metrics: List of metric identifiers to enable, or "all" for all registered metrics. - If None, enables no metrics (empty list). + metrics: List of metric identifiers to enable, "all" for all registered + metrics, or None to disable all metrics. """ if metrics == "all": self.enabled_metrics = set(self._registered_metrics.keys()) elif isinstance(metrics, (list, set)): - # Only enable metrics that are registered - valid_metrics = set(metrics) & set(self._registered_metrics.keys()) - invalid_metrics = set(metrics) - set(self._registered_metrics.keys()) - if invalid_metrics: - print( - f"Warning: Attempting to enable unregistered metrics: {invalid_metrics}" - ) - self.enabled_metrics = valid_metrics + self._enable_selected_metrics(metrics) else: - # Default to empty set self.enabled_metrics = set() - def log(self, identifier: str, value: Any, metadata: Dict[str, Any] = None) -> None: - """Log a metric value with optional metadata. Location is auto-inferred. + def _enable_selected_metrics(self, metrics: Union[List[str], set]) -> None: + """Enable only the selected metrics that are registered. + + Args: + metrics: List or set of metric identifiers to enable. + """ + valid_metrics = set(metrics) & set(self._registered_metrics.keys()) + invalid_metrics = set(metrics) - set(self._registered_metrics.keys()) + + if invalid_metrics: + print( + f"Warning: Attempting to enable unregistered metrics: {invalid_metrics}" + ) + + self.enabled_metrics = valid_metrics + + def log(self, identifier: str, value: Any, metadata: Optional[Dict[str, Any]] = None) -> None: + """Log a metric value with optional metadata. - This only works if log_path is defined. + Location is auto-inferred from the calling context. This only works if log_path is defined. + + Args: + identifier: Unique string identifier for the metric. + value: The metric value to log. + metadata: Optional additional context information. + """ + if not self._should_log_metric(identifier): + return + + if not self._is_within_limits(): + return + + if not self._passes_sampling(): + return + + event = self._create_log_event(identifier, value, metadata) + self._add_event_and_flush_if_needed(event) + + def _should_log_metric(self, identifier: str) -> bool: + """Check if the metric should be logged based on configuration. + + Args: + identifier: Metric identifier to check. + + Returns: + True if the metric should be logged, False otherwise. """ - # Check if logging is configured if self.log_path is None: print( - f"Warning: Cannot log metric '{identifier}' - log_path not defined. Use configure_logging() first." + f"Warning: Cannot log metric '{identifier}' - log_path not defined. " + "Use configure_logging() first." ) - return + return False - # Check if metric is enabled if identifier not in self.enabled_metrics: print( f"Warning: Attempting to log metric '{identifier}' which is not enabled" ) - return + return False + + return True - # Check if max_records limit has been reached - if ( + def _is_within_limits(self) -> bool: + """Check if logging is within configured limits. + + Returns: + True if within limits, False if max records reached. + """ + return not ( self.max_records is not None and self._total_records_logged >= self.max_records - ): - return # Silently ignore - we've hit the limit - - # Apply sampling factor - if self.sampling_factor < 1.0 and random.random() > self.sampling_factor: - return # Event not selected for logging due to sampling + ) - # Create log event - event = LogEvent( + def _passes_sampling(self) -> bool: + """Check if event passes sampling filter. + + Returns: + True if event should be logged based on sampling factor. + """ + return self.sampling_factor >= 1.0 or random.random() <= self.sampling_factor + + def _create_log_event( + self, + identifier: str, + value: Any, + metadata: Optional[Dict[str, Any]] + ) -> LogEvent: + """Create a log event from the provided data. + + Args: + identifier: Metric identifier. + value: Metric value. + metadata: Optional metadata. + + Returns: + LogEvent instance ready for logging. + """ + return LogEvent( timestamp=datetime.now(), metric=identifier, value=value, @@ -190,75 +360,129 @@ def log(self, identifier: str, value: Any, metadata: Dict[str, Any] = None) -> N location=self._get_calling_location(), ) - # Add to queue and increment counter + def _add_event_and_flush_if_needed(self, event: LogEvent) -> None: + """Add event to queue and flush if threshold is reached. + + Args: + event: LogEvent to add to the queue. + """ self.log_queue.append(event) self._total_records_logged += 1 - # Check if we should flush if len(self.log_queue) >= self.flush_every: self.flush() def configure_logging( self, log_path: str, - enabled_metrics: Union[List[str], str] = None, + enabled_metrics: Union[List[str], str, None] = None, max_records: Optional[int] = None, sampling_factor: float = 1.0, ) -> None: """Configure logging with a log path and optionally enable metrics. This must be called before logging can work. Resets the total records counter. + + Args: + log_path: Directory path where log files will be written. + enabled_metrics: List of metric identifiers to enable, "all", or None. + max_records: Maximum number of records to log (None for unlimited). + sampling_factor: Probability of logging each event (0.0-1.0). """ self.log_path = log_path self._ensure_log_directory() self.enable_metrics(enabled_metrics) + self._update_logging_limits(max_records, sampling_factor) + self._total_records_logged = 0 - # Update limits if provided + def _update_logging_limits(self, max_records: Optional[int], sampling_factor: float) -> None: + """Update logging limits and sampling factor. + + Args: + max_records: Maximum records limit. + sampling_factor: Event sampling probability. + """ self.max_records = max_records self.sampling_factor = max(0.0, min(1.0, sampling_factor)) - # Reset the total records counter when reconfiguring - self._total_records_logged = 0 - def flush(self) -> None: - """Force flush the current queue to disk.""" + """Force flush the current queue to disk. + + Writes all queued events to the log file in JSONL format. + """ if not self.log_queue or self.log_path is None: return - # Get current timestamp for filename - filename = "micro_metrics.jsonl" - filepath = os.path.join(self.log_path, filename) + filepath = os.path.join(self.log_path, "micro_metrics.jsonl") + self._write_events_to_file(filepath) + self.last_flush_time = time.time() - # Write events to file + def _write_events_to_file(self, filepath: str) -> None: + """Write all queued events to the specified file. + + Args: + filepath: Path to the log file. + """ with open(filepath, "a", encoding="utf-8") as f: while self.log_queue: event = self.log_queue.popleft() - # Convert dataclass to dict and serialize - event_dict = asdict(event) - # Convert datetime to ISO format string - event_dict["timestamp"] = event_dict["timestamp"].isoformat() + event_dict = self._serialize_event(event) f.write(json.dumps(event_dict) + "\n") - self.last_flush_time = time.time() + def _serialize_event(self, event: LogEvent) -> Dict[str, Any]: + """Serialize a log event to a dictionary. + + Args: + event: LogEvent to serialize. + + Returns: + Dictionary representation of the event. + """ + event_dict = asdict(event) + event_dict["timestamp"] = event_dict["timestamp"].isoformat() + return event_dict def is_metric_enabled(self, identifier: str) -> bool: - """Check if a specific metric is requested for logging.""" + """Check if a specific metric is enabled for logging. + + Args: + identifier: Metric identifier to check. + + Returns: + True if the metric is enabled, False otherwise. + """ return identifier in self.enabled_metrics def get_enabled_metrics(self) -> set: - """Get currently enabled metrics.""" + """Get currently enabled metrics. + + Returns: + Set of enabled metric identifiers. + """ return self.enabled_metrics.copy() def is_logging_configured(self) -> bool: - """Check if logging is configured (log_path is set).""" + """Check if logging is configured. + + Returns: + True if log_path is set, False otherwise. + """ return self.log_path is not None def get_total_records_logged(self) -> int: - """Get the total number of records logged since initialization or last configure_logging call.""" + """Get the total number of records logged. + + Returns: + Number of records logged since initialization or last configure_logging call. + """ return getattr(self, "_total_records_logged", 0) def is_max_records_reached(self) -> bool: - """Check if the maximum number of records has been reached.""" + """Check if the maximum number of records has been reached. + + Returns: + True if max records limit has been reached, False otherwise. + """ if self.max_records is None: return False return self.get_total_records_logged() >= self.max_records @@ -274,9 +498,17 @@ def get_records_remaining(self) -> Optional[int]: return max(0, self.max_records - self.get_total_records_logged()) def get_sampling_factor(self) -> float: - """Get the current sampling factor.""" + """Get the current sampling factor. + + Returns: + Current sampling factor (0.0-1.0). + """ return getattr(self, "sampling_factor", 1.0) def get_max_records(self) -> Optional[int]: - """Get the current max_records limit.""" + """Get the current max_records limit. + + Returns: + Maximum records limit, or None if no limit is set. + """ return getattr(self, "max_records", None) diff --git a/sparse_attention_hub/plotting/generator.py b/sparse_attention_hub/plotting/generator.py index 61b317ca..8d4461ae 100644 --- a/sparse_attention_hub/plotting/generator.py +++ b/sparse_attention_hub/plotting/generator.py @@ -4,19 +4,35 @@ from typing import Any, Dict, Optional import matplotlib.pyplot as plt +import numpy as np import seaborn as sns from .granularity import Granularity class PlotGenerator: - """Generates plots for sparse attention analysis.""" - - def __init__(self, storage_path: str = "./plots"): + """Generates plots for sparse attention analysis. + + This class provides functionality to generate various types of plots + for analyzing sparse attention patterns at different granularities. + + Attributes: + storage_path: Directory path where generated plots will be saved. + """ + + def __init__(self, storage_path: str = "./plots") -> None: + """Initialize the PlotGenerator. + + Args: + storage_path: Directory path for storing generated plots. + Defaults to "./plots". + """ self.storage_path = storage_path self._ensure_storage_directory() + self._setup_plotting_style() - # Set up plotting style + def _setup_plotting_style(self) -> None: + """Configure matplotlib and seaborn plotting styles.""" plt.style.use("default") sns.set_palette("husl") @@ -34,105 +50,160 @@ def generate_plot( """Generate a plot with specified granularity. Args: - granularity: Level of granularity for the plot - data: Data to plot (if None, generates sample data) - plot_type: Type of plot to generate - **kwargs: Additional plotting parameters + granularity: Level of granularity for the plot (per token, head, or layer). + data: Optional data to plot. If None, generates sample data for demonstration. + plot_type: Type of plot to generate. Currently unused but reserved for future extensions. + **kwargs: Additional plotting parameters passed to the plot generation methods. Returns: - Path to the generated plot file + Absolute path to the generated plot file. + + Raises: + ValueError: If the specified granularity is not supported. """ if granularity == Granularity.PER_TOKEN: - return self._generate_plot_1(granularity, data, **kwargs) + return self._generate_line_plot(granularity, data, **kwargs) elif granularity == Granularity.PER_HEAD: - return self._generate_plot_2(granularity, data, **kwargs) + return self._generate_heatmap_plot(granularity, data, **kwargs) elif granularity == Granularity.PER_LAYER: - return self._generate_plot_1(granularity, data, **kwargs) + return self._generate_line_plot(granularity, data, **kwargs) else: raise ValueError(f"Unsupported granularity: {granularity}") - def _generate_plot_1( + def _generate_line_plot( self, granularity: Granularity, data: Optional[Dict[str, Any]] = None, **kwargs: Any, ) -> str: - """Generate plot type 1 (line plots, attention patterns). + """Generate line plots for attention patterns. Args: - granularity: Level of granularity - data: Data to plot - **kwargs: Additional parameters + granularity: Level of granularity (per token or per layer). + data: Optional data to plot. If None, generates sample data. + **kwargs: Additional plotting parameters. Returns: - Path to generated plot + Path to the generated plot file. """ - # TODO: Implement plot generation fig, ax = plt.subplots(figsize=(10, 6)) - + if data is None: - # Generate sample data for demonstration - import numpy as np - - x = np.linspace(0, 10, 100) - y = np.sin(x) + np.random.normal(0, 0.1, 100) - ax.plot(x, y, label=f"Sample {granularity.value} data") + self._plot_sample_line_data(ax, granularity) else: - # Plot actual data - # Implementation depends on data structure - pass + self._plot_actual_line_data(ax, data) + + self._configure_line_plot_axes(ax, granularity) + return self._save_plot(fig, "plot", granularity, data) + + def _plot_sample_line_data(self, ax: plt.Axes, granularity: Granularity) -> None: + """Plot sample line data for demonstration. + + Args: + ax: Matplotlib axes object to plot on. + granularity: Granularity level for labeling. + """ + x = np.linspace(0, 10, 100) + y = np.sin(x) + np.random.normal(0, 0.1, 100) + ax.plot(x, y, label=f"Sample {granularity.value} data") - ax.set_title( - f"Sparse Attention Analysis - {granularity.value.replace('_', ' ').title()}" - ) + def _plot_actual_line_data(self, ax: plt.Axes, data: Dict[str, Any]) -> None: + """Plot actual line data from provided data dictionary. + + Args: + ax: Matplotlib axes object to plot on. + data: Data dictionary containing plot information. + """ + # Implementation depends on data structure + # This is a placeholder for future actual data plotting + pass + + def _configure_line_plot_axes(self, ax: plt.Axes, granularity: Granularity) -> None: + """Configure axes for line plots. + + Args: + ax: Matplotlib axes object to configure. + granularity: Granularity level for title formatting. + """ + title = f"Sparse Attention Analysis - {granularity.value.replace('_', ' ').title()}" + ax.set_title(title) ax.set_xlabel("Position") ax.set_ylabel("Attention Weight") ax.legend() ax.grid(True, alpha=0.3) - # Save plot - filename = f"plot_{granularity.value}_{hash(str(data))}.png" - filepath = os.path.join(self.storage_path, filename) - plt.savefig(filepath, dpi=300, bbox_inches="tight") - plt.close() - - return filepath - - def _generate_plot_2( + def _generate_heatmap_plot( self, granularity: Granularity, data: Optional[Dict[str, Any]] = None, **kwargs: Any, ) -> str: - """Generate plot type 2 (heatmaps, attention matrices). + """Generate heatmaps for attention matrices. Args: - granularity: Level of granularity - data: Data to plot - **kwargs: Additional parameters + granularity: Level of granularity (typically per head). + data: Optional data containing attention matrix. If None, generates sample data. + **kwargs: Additional plotting parameters. Returns: - Path to generated plot + Path to the generated plot file. + + Raises: + ValueError: If data is provided but doesn't contain required attention_matrix. """ - # TODO: Implement heatmap generation fig, ax = plt.subplots(figsize=(8, 8)) - + + attention_matrix = self._get_attention_matrix(granularity, data) + self._create_heatmap(ax, attention_matrix) + self._configure_heatmap_axes(ax, granularity) + + return self._save_plot(fig, "heatmap", granularity, data) + + def _get_attention_matrix( + self, + granularity: Granularity, + data: Optional[Dict[str, Any]] + ) -> np.ndarray: + """Get attention matrix from data or generate sample data. + + Args: + granularity: Granularity level for determining matrix size. + data: Optional data dictionary containing attention matrix. + + Returns: + Attention matrix as numpy array. + + Raises: + ValueError: If data is provided but doesn't contain attention_matrix. + """ if data is None: - # Generate sample attention matrix - import numpy as np - - size = 12 if granularity == Granularity.PER_HEAD else 8 - attention_matrix = np.random.rand(size, size) - attention_matrix = ( - attention_matrix + attention_matrix.T - ) / 2 # Make symmetric - else: - # Use actual data - attention_matrix = data.get("attention_matrix", None) - if attention_matrix is None: - raise ValueError("attention_matrix required in data for heatmap") + return self._generate_sample_attention_matrix(granularity) + + attention_matrix = data.get("attention_matrix") + if attention_matrix is None: + raise ValueError("attention_matrix required in data for heatmap") + return attention_matrix + + def _generate_sample_attention_matrix(self, granularity: Granularity) -> np.ndarray: + """Generate sample attention matrix for demonstration. + + Args: + granularity: Granularity level for determining matrix size. + + Returns: + Symmetric attention matrix. + """ + size = 12 if granularity == Granularity.PER_HEAD else 8 + attention_matrix = np.random.rand(size, size) + return (attention_matrix + attention_matrix.T) / 2 # Make symmetric - # Create heatmap + def _create_heatmap(self, ax: plt.Axes, attention_matrix: np.ndarray) -> None: + """Create heatmap visualization. + + Args: + ax: Matplotlib axes object to plot on. + attention_matrix: Attention matrix to visualize. + """ sns.heatmap( attention_matrix, annot=True, @@ -142,56 +213,92 @@ def _generate_plot_2( cbar_kws={"label": "Attention Weight"}, ) - ax.set_title( - f"Attention Matrix - {granularity.value.replace('_', ' ').title()}" - ) + def _configure_heatmap_axes(self, ax: plt.Axes, granularity: Granularity) -> None: + """Configure axes for heatmap plots. + + Args: + ax: Matplotlib axes object to configure. + granularity: Granularity level for title formatting. + """ + title = f"Attention Matrix - {granularity.value.replace('_', ' ').title()}" + ax.set_title(title) ax.set_xlabel("Key Position") ax.set_ylabel("Query Position") - # Save plot - filename = f"heatmap_{granularity.value}_{hash(str(data))}.png" + def _save_plot( + self, + fig: plt.Figure, + plot_type: str, + granularity: Granularity, + data: Optional[Dict[str, Any]] + ) -> str: + """Save plot to file and close figure. + + Args: + fig: Matplotlib figure object to save. + plot_type: Type of plot for filename. + granularity: Granularity level for filename. + data: Data used for generating unique filename hash. + + Returns: + Absolute path to the saved plot file. + """ + filename = f"{plot_type}_{granularity.value}_{hash(str(data))}.png" filepath = os.path.join(self.storage_path, filename) - plt.savefig(filepath, dpi=300, bbox_inches="tight") - plt.close() - + fig.savefig(filepath, dpi=300, bbox_inches="tight") + plt.close(fig) return filepath def generate_comparison_plot( - self, data_dict: Dict[str, Any], granularity: Granularity + self, + data_dict: Dict[str, Any], + granularity: Granularity ) -> str: """Generate comparison plot for multiple datasets. Args: - data_dict: Dictionary mapping labels to data - granularity: Level of granularity + data_dict: Dictionary mapping dataset labels to their corresponding data. + granularity: Level of granularity for the comparison plot. Returns: - Path to generated comparison plot + Path to the generated comparison plot file. """ fig, ax = plt.subplots(figsize=(12, 8)) - + + self._plot_comparison_data(ax, data_dict) + self._configure_comparison_axes(ax, granularity) + + return self._save_plot(fig, "comparison", granularity, data_dict) + + def _plot_comparison_data(self, ax: plt.Axes, data_dict: Dict[str, Any]) -> None: + """Plot comparison data for multiple datasets. + + Args: + ax: Matplotlib axes object to plot on. + data_dict: Dictionary mapping labels to data. + """ for label, data in data_dict.items(): - # Plot each dataset - # Implementation depends on data structure + # Plot each dataset - implementation depends on data structure + # This is a placeholder for future actual data plotting pass - ax.set_title(f"Comparison - {granularity.value.replace('_', ' ').title()}") + def _configure_comparison_axes(self, ax: plt.Axes, granularity: Granularity) -> None: + """Configure axes for comparison plots. + + Args: + ax: Matplotlib axes object to configure. + granularity: Granularity level for title formatting. + """ + title = f"Comparison - {granularity.value.replace('_', ' ').title()}" + ax.set_title(title) ax.legend() ax.grid(True, alpha=0.3) - # Save plot - filename = f"comparison_{granularity.value}_{hash(str(data_dict))}.png" - filepath = os.path.join(self.storage_path, filename) - plt.savefig(filepath, dpi=300, bbox_inches="tight") - plt.close() - - return filepath - def set_storage_path(self, path: str) -> None: - """Set the storage path for plots. + """Set the storage path for generated plots. Args: - path: New storage path + path: New directory path where plots will be saved. """ self.storage_path = path self._ensure_storage_directory() diff --git a/sparse_attention_hub/sparse_attention/efficient_attention/base.py b/sparse_attention_hub/sparse_attention/efficient_attention/base.py index 0d1b5f01..98fe1678 100644 --- a/sparse_attention_hub/sparse_attention/efficient_attention/base.py +++ b/sparse_attention_hub/sparse_attention/efficient_attention/base.py @@ -1,9 +1,8 @@ """Base classes for efficient attention mechanisms.""" - from abc import abstractmethod from dataclasses import dataclass -from typing import Any, Dict, Optional, Tuple +from typing import Any, Dict, Optional, Tuple, Type, cast import torch from torch import nn @@ -13,13 +12,22 @@ @dataclass class EfficientAttentionConfig(SparseAttentionConfig): - """Configuration class for efficient attention mechanisms.""" + """Configuration class for efficient attention mechanisms. + + This is a base configuration class for production-ready sparse attention + implementations that prioritize efficiency and performance. + """ pass class EfficientAttention(SparseAttention): - """Abstract base class for efficient attention mechanisms.""" + """Abstract base class for efficient attention mechanisms. + + This class serves as the base for production-ready sparse attention + implementations that are optimized for performance and memory efficiency, + such as HashAttention and DoubleSparsity. + """ def __init__(self, sparse_attention_config: SparseAttentionConfig) -> None: """Initialize efficient attention mechanism. @@ -54,19 +62,30 @@ def create_from_config(cls, config: SparseAttentionConfig) -> "EfficientAttentio Args: config: Configuration for the efficient attention mechanism. + Must be an instance of EfficientAttentionConfig. Returns: Instance of the efficient attention mechanism. Raises: TypeError: If config is not an EfficientAttentionConfig. + ValueError: If no implementation is found for the config type. """ if not isinstance(config, EfficientAttentionConfig): raise TypeError(f"Expected EfficientAttentionConfig, got {type(config)}") - # Import here to avoid circular imports - from typing import Type, cast + registry = cls._get_implementation_registry() + concrete_class = cls._get_concrete_class(config, registry) + return concrete_class.create_from_config(config) + @classmethod + def _get_implementation_registry(cls) -> Dict[Type[EfficientAttentionConfig], Type["EfficientAttention"]]: + """Get the registry mapping config types to implementation classes. + + Returns: + Dictionary mapping config types to their corresponding implementation classes. + """ + # Import here to avoid circular imports from .implementations import ( DoubleSparsity, DoubleSparsityConfig, @@ -74,26 +93,32 @@ def create_from_config(cls, config: SparseAttentionConfig) -> "EfficientAttentio HashAttentionConfig, ) - # Registry mapping config types to concrete efficient attention classes - _EFFICIENT_ATTENTION_REGISTRY: Dict[ - Type[EfficientAttentionConfig], Type[EfficientAttention] - ] = { + return { DoubleSparsityConfig: DoubleSparsity, HashAttentionConfig: HashAttention, } - # Look up the concrete class based on the config type - concrete_class: Optional[ - Type[EfficientAttention] - ] = _EFFICIENT_ATTENTION_REGISTRY.get(type(config)) + @classmethod + def _get_concrete_class( + cls, + config: EfficientAttentionConfig, + registry: Dict[Type[EfficientAttentionConfig], Type["EfficientAttention"]] + ) -> Type["EfficientAttention"]: + """Get the concrete implementation class for the given configuration. + + Args: + config: Configuration instance. + registry: Registry mapping config types to implementation classes. + + Returns: + Concrete implementation class. + + Raises: + ValueError: If no implementation is found for the config type. + """ + concrete_class = registry.get(type(config)) if concrete_class is None: raise ValueError( f"No efficient attention class found for config type: {type(config)}" ) - - # Cast to help mypy understand the type - concrete_class: Type[EfficientAttention] = cast( - Type[EfficientAttention], concrete_class - ) - # Call the concrete class's create_from_config method - return concrete_class.create_from_config(config) + return cast(Type["EfficientAttention"], concrete_class) diff --git a/sparse_attention_hub/sparse_attention/research_attention/base.py b/sparse_attention_hub/sparse_attention/research_attention/base.py index 34189068..12e96149 100644 --- a/sparse_attention_hub/sparse_attention/research_attention/base.py +++ b/sparse_attention_hub/sparse_attention/research_attention/base.py @@ -23,13 +23,28 @@ @dataclass class ResearchAttentionConfig(SparseAttentionConfig): - """Configuration class for research attention mechanisms.""" + """Configuration class for research attention mechanisms. + + This configuration specifies the masker components that will be applied + sequentially to create sparse attention patterns for research purposes. + + Attributes: + masker_configs: List of masker configurations to apply in sequence. + """ masker_configs: List[MaskerConfig] class ResearchAttention(SparseAttention): - """Base class for research attention mechanisms with maskers.""" + """Base class for research attention mechanisms with configurable maskers. + + This class implements sparse attention by applying a sequence of maskers + to create custom attention patterns. It supports metrics logging and + validation of masker configurations. + + Attributes: + maskers: List of research maskers to apply sequentially. + """ maskers: List[ResearchMasker] @@ -42,24 +57,33 @@ def __init__( Args: sparse_attention_config: Configuration for the sparse attention mechanism. - maskers: List of research maskers to apply. + maskers: List of research maskers to apply in sequence. Raises: ValueError: If more than one sampling masker is provided. """ super().__init__(sparse_attention_config) + self._validate_masker_configuration(maskers) + self.maskers = maskers - # Validate that there's at most one sampling masker - sampling_masker_count: int = sum( + def _validate_masker_configuration(self, maskers: List[ResearchMasker]) -> None: + """Validate the masker configuration. + + Args: + maskers: List of maskers to validate. + + Raises: + ValueError: If more than one sampling masker is provided. + """ + sampling_masker_count = sum( 1 for masker in maskers if isinstance(masker, SamplingMasker) ) if sampling_masker_count > 1: raise ValueError( - "Only one sampling masker supported for efficiency; consider implementing all sampling logic in one masker" + "Only one sampling masker supported for efficiency; " + "consider implementing all sampling logic in one masker" ) - self.maskers = maskers - def custom_attention( self, module: nn.Module, @@ -75,30 +99,106 @@ def custom_attention( """Compute research attention mechanism with masking. Args: - module: The attention module - queries: Query tensor of shape (b, h, sk, d) - keys: Key tensor of shape (b, h, sq, d) - values: Value tensor of shape (b, h, sq, d) - attention_mask: Optional attention mask of shape (b, h, sq, sk) - scaling: Scaling factor for attention weights - dropout: Dropout probability - **kwargs: Additional keyword arguments + module: The attention module. + queries: Query tensor of shape (b, h, sk, d). + keys: Key tensor of shape (b, h, sq, d). + values: Value tensor of shape (b, h, sq, d). + attention_mask: Optional attention mask of shape (b, h, sq, sk). + scaling: Scaling factor for attention weights. + dropout: Dropout probability. + sparse_meta_data: Additional metadata for sparse attention computation. + **kwargs: Additional keyword arguments. Returns: Tuple of attention output and optional attention weights. """ - # Create an empty Mask object - mask_shape: Tuple[int, int, int, int] = ( + sparse_attention_mask = self._create_initial_mask(queries, keys) + sparse_attention_mask = self._apply_maskers( + sparse_attention_mask=sparse_attention_mask, + keys=keys, + queries=queries, + values=values, + attention_mask=attention_mask, + scaling=scaling, + dropout=dropout, + sparse_meta_data=sparse_meta_data, + **kwargs, + ) + + self._log_attention_density(sparse_attention_mask, kwargs) + + attention_output, attention_weights = self._compute_masked_attention( + module=module, + queries=queries, + keys=keys, + values=values, + attention_mask=attention_mask, + scaling=scaling, + dropout=dropout, + sparse_attention_mask=sparse_attention_mask, + **kwargs, + ) + + self._log_attention_error( + module=module, + queries=queries, + keys=keys, + values=values, + attention_mask=attention_mask, + scaling=scaling, + dropout=dropout, + attention_output=attention_output, + **kwargs, + ) + + return attention_output, attention_weights + + def _create_initial_mask(self, queries: torch.Tensor, keys: torch.Tensor) -> Mask: + """Create an initial empty mask for the attention computation. + + Args: + queries: Query tensor. + keys: Key tensor. + + Returns: + Empty mask with appropriate shape. + """ + mask_shape = ( queries.shape[0], queries.shape[1], queries.shape[2], keys.shape[2], ) - sparse_attention_mask: Mask = Mask.create_empty_mask( - mask_shape, dtype=queries.dtype - ) + return Mask.create_empty_mask(mask_shape, dtype=queries.dtype) - # Apply all maskers sequentially, each one on the output of the previous one + def _apply_maskers( + self, + sparse_attention_mask: Mask, + keys: torch.Tensor, + queries: torch.Tensor, + values: torch.Tensor, + attention_mask: Optional[torch.Tensor], + scaling: float, + dropout: float, + sparse_meta_data: Dict[Any, Any], + **kwargs: Dict[str, Any], + ) -> Mask: + """Apply all maskers sequentially to create the final sparse attention mask. + + Args: + sparse_attention_mask: Initial mask to start with. + keys: Key tensor. + queries: Query tensor. + values: Value tensor. + attention_mask: Optional attention mask. + scaling: Scaling factor. + dropout: Dropout probability. + sparse_meta_data: Additional metadata. + **kwargs: Additional keyword arguments. + + Returns: + Final sparse attention mask after applying all maskers. + """ for masker in self.maskers: sparse_attention_mask = masker.add_mask( keys=keys, @@ -111,19 +211,51 @@ def custom_attention( previous_mask=sparse_attention_mask, **kwargs, ) + return sparse_attention_mask + def _log_attention_density(self, sparse_attention_mask: Mask, kwargs: Dict[str, Any]) -> None: + """Log attention density metric if enabled. + + Args: + sparse_attention_mask: The sparse attention mask. + kwargs: Keyword arguments containing layer information. + """ if MicroMetricLogger().is_metric_enabled("research_attention_density"): MicroMetricLogger().log( "research_attention_density", sparse_attention_mask.get_density(), - metadata={"layer_idx": kwargs["layer_idx"]}, + metadata={"layer_idx": kwargs.get("layer_idx")}, ) - # Call compute_masked_attention_output on the result of the last mask - # Always request attention weights to match the expected return signature - attention_output: torch.Tensor - attention_weights: torch.Tensor - attention_output, attention_weights = get_masked_attention_output( + def _compute_masked_attention( + self, + module: nn.Module, + queries: torch.Tensor, + keys: torch.Tensor, + values: torch.Tensor, + attention_mask: Optional[torch.Tensor], + scaling: float, + dropout: float, + sparse_attention_mask: Mask, + **kwargs: Dict[str, Any], + ) -> Tuple[torch.Tensor, torch.Tensor]: + """Compute the masked attention output and weights. + + Args: + module: The attention module. + queries: Query tensor. + keys: Key tensor. + values: Value tensor. + attention_mask: Optional attention mask. + scaling: Scaling factor. + dropout: Dropout probability. + sparse_attention_mask: Sparse attention mask. + **kwargs: Additional keyword arguments. + + Returns: + Tuple of attention output and attention weights. + """ + return get_masked_attention_output( module=module, queries=queries, keys=keys, @@ -136,6 +268,31 @@ def custom_attention( **kwargs, ) + def _log_attention_error( + self, + module: nn.Module, + queries: torch.Tensor, + keys: torch.Tensor, + values: torch.Tensor, + attention_mask: Optional[torch.Tensor], + scaling: float, + dropout: float, + attention_output: torch.Tensor, + **kwargs: Dict[str, Any], + ) -> None: + """Log attention output error metric if enabled. + + Args: + module: The attention module. + queries: Query tensor. + keys: Key tensor. + values: Value tensor. + attention_mask: Optional attention mask. + scaling: Scaling factor. + dropout: Dropout probability. + attention_output: Computed attention output. + **kwargs: Additional keyword arguments. + """ if MicroMetricLogger().is_metric_enabled("research_attention_output_error"): true_attention_output, _ = get_true_attention_output( module, @@ -153,20 +310,19 @@ def custom_attention( MicroMetricLogger().log( "research_attention_output_error", float(error.item()), - metadata={"layer_idx": kwargs["layer_idx"]}, + metadata={"layer_idx": kwargs.get("layer_idx")}, ) - return attention_output, attention_weights - @classmethod def create_from_config(cls, config: SparseAttentionConfig) -> "ResearchAttention": """Create research attention instance from configuration. Args: config: Configuration for the research attention mechanism. + Must be an instance of ResearchAttentionConfig. Returns: - Instance of the research attention mechanism. + Instance of the research attention mechanism with configured maskers. Raises: TypeError: If config is not a ResearchAttentionConfig. @@ -174,12 +330,21 @@ def create_from_config(cls, config: SparseAttentionConfig) -> "ResearchAttention if not isinstance(config, ResearchAttentionConfig): raise TypeError(f"Expected ResearchAttentionConfig, got {type(config)}") - # Create ResearchMasker objects from the configs using the factory method - maskers: List[ResearchMasker] = [] - for masker_config in config.masker_configs: - masker: ResearchMasker = ResearchMasker.create_masker_from_config( - masker_config - ) - maskers.append(masker) - + maskers = cls._create_maskers_from_config(config.masker_configs) return cls(config, maskers) + + @classmethod + def _create_maskers_from_config(cls, masker_configs: List[MaskerConfig]) -> List[ResearchMasker]: + """Create research masker objects from their configurations. + + Args: + masker_configs: List of masker configurations. + + Returns: + List of configured research masker instances. + """ + maskers = [] + for masker_config in masker_configs: + masker = ResearchMasker.create_masker_from_config(masker_config) + maskers.append(masker) + return maskers diff --git a/sparse_attention_hub/sparse_attention/utils/hashattention_utils.py b/sparse_attention_hub/sparse_attention/utils/hashattention_utils.py index ba8b5aea..d99eabeb 100644 --- a/sparse_attention_hub/sparse_attention/utils/hashattention_utils.py +++ b/sparse_attention_hub/sparse_attention/utils/hashattention_utils.py @@ -1,10 +1,18 @@ +"""Utilities for converting and loading HashAttention weights. + +This module provides functions to convert USA (Universal Sparse Attention) +checkpoint weights to HashAttention format and load them for model use. + +Note: + Currently only supports 3-layered MLPs. Support for other configurations + needs to be implemented. +""" + import pickle from typing import Dict, List import torch -""" This only works for 3 layered MLPs. Need to fix for other cases""" - def convert_usa_weights_to_hash_attention( usa_checkpoint_path: str, @@ -16,90 +24,24 @@ def convert_usa_weights_to_hash_attention( """Convert USA module weights to HashAttentionTopKMasker format. Args: - usa_checkpoint_path: Path to USA checkpoint file - num_layers: Number of layers in the model - num_heads: Number of attention heads - num_mlp_layers: Number of MLP layers (default: 3) - device: Device to load weights on + usa_checkpoint_path: Path to the USA checkpoint file. + num_layers: Number of transformer layers in the model. Defaults to 32. + num_heads: Number of attention heads per layer. Defaults to 32. + num_mlp_layers: Number of MLP layers in the hash transformation. Defaults to 3. + device: Device to load the weights on ("cpu", "cuda", etc.). Defaults to "cpu". Returns: - Dictionary of layer-wise weights in HashAttention format + Dictionary mapping layer indices to their corresponding weights in HashAttention format. + Each layer contains "query_matrix", "query_bias", "key_matrix", and "key_bias" lists. """ - print(f"Loading USA weights from {usa_checkpoint_path}") usa_state_dict = torch.load(usa_checkpoint_path, map_location=device) hat_weights = {} - for layer_idx in range(num_layers): - layer_weights = { - "query_matrix": [], - "query_bias": [], - "key_matrix": [], - "key_bias": [], - } - - # Collect weights for all heads in this layer - query_matrices_per_layer = [[] for _ in range(num_mlp_layers)] - query_biases_per_layer = [[] for _ in range(num_mlp_layers)] - key_matrices_per_layer = [[] for _ in range(num_mlp_layers)] - key_biases_per_layer = [[] for _ in range(num_mlp_layers)] - - for head_idx in range(num_heads): - query_prefix = f"{layer_idx}.learning_to_hash_transformation_q.{head_idx}" - key_prefix = f"{layer_idx}.learning_to_hash_transformation_k.{head_idx}" - - # Extract weights from MLP layers (linear layers at indices 0, 2, 4, ...) - linear_indices = [i * 2 for i in range(num_mlp_layers)] - for i, linear_idx in enumerate(linear_indices): - # Query weights - weight_key = f"{query_prefix}.{linear_idx}.weight" - bias_key = f"{query_prefix}.{linear_idx}.bias" - - if weight_key in usa_state_dict: - weight = usa_state_dict[ - weight_key - ].t() # Transpose to (in_features, out_features) - query_matrices_per_layer[i].append(weight) - - if bias_key in usa_state_dict: - query_biases_per_layer[i].append(usa_state_dict[bias_key]) - else: - query_biases_per_layer[i].append( - torch.zeros(usa_state_dict[weight_key].shape[0]) - ) - - # Key weights - weight_key = f"{key_prefix}.{linear_idx}.weight" - bias_key = f"{key_prefix}.{linear_idx}.bias" - - if weight_key in usa_state_dict: - weight = usa_state_dict[ - weight_key - ].t() # Transpose to (in_features, out_features) - key_matrices_per_layer[i].append(weight) - - if bias_key in usa_state_dict: - key_biases_per_layer[i].append(usa_state_dict[bias_key]) - else: - key_biases_per_layer[i].append( - torch.zeros(usa_state_dict[weight_key].shape[0]) - ) - - # Stack all heads for each layer - for i in range(num_mlp_layers): - if query_matrices_per_layer[i]: - layer_weights["query_matrix"].append( - torch.stack(query_matrices_per_layer[i]) - ) - layer_weights["query_bias"].append( - torch.stack(query_biases_per_layer[i]) - ) - layer_weights["key_matrix"].append( - torch.stack(key_matrices_per_layer[i]) - ) - layer_weights["key_bias"].append(torch.stack(key_biases_per_layer[i])) - + layer_weights = _convert_layer_weights( + usa_state_dict, layer_idx, num_heads, num_mlp_layers + ) hat_weights[layer_idx] = layer_weights print( @@ -108,6 +50,202 @@ def convert_usa_weights_to_hash_attention( return hat_weights +def _convert_layer_weights( + usa_state_dict: Dict[str, torch.Tensor], + layer_idx: int, + num_heads: int, + num_mlp_layers: int, +) -> Dict[str, List[torch.Tensor]]: + """Convert weights for a single layer. + + Args: + usa_state_dict: USA checkpoint state dictionary. + layer_idx: Index of the layer to process. + num_heads: Number of attention heads. + num_mlp_layers: Number of MLP layers. + + Returns: + Dictionary containing converted weights for the layer. + """ + layer_weights = { + "query_matrix": [], + "query_bias": [], + "key_matrix": [], + "key_bias": [], + } + + # Collect weights for all heads in this layer + query_matrices_per_layer = [[] for _ in range(num_mlp_layers)] + query_biases_per_layer = [[] for _ in range(num_mlp_layers)] + key_matrices_per_layer = [[] for _ in range(num_mlp_layers)] + key_biases_per_layer = [[] for _ in range(num_mlp_layers)] + + for head_idx in range(num_heads): + _extract_head_weights( + usa_state_dict=usa_state_dict, + layer_idx=layer_idx, + head_idx=head_idx, + num_mlp_layers=num_mlp_layers, + query_matrices_per_layer=query_matrices_per_layer, + query_biases_per_layer=query_biases_per_layer, + key_matrices_per_layer=key_matrices_per_layer, + key_biases_per_layer=key_biases_per_layer, + ) + + # Stack all heads for each MLP layer + _stack_head_weights( + layer_weights=layer_weights, + num_mlp_layers=num_mlp_layers, + query_matrices_per_layer=query_matrices_per_layer, + query_biases_per_layer=query_biases_per_layer, + key_matrices_per_layer=key_matrices_per_layer, + key_biases_per_layer=key_biases_per_layer, + ) + + return layer_weights + + +def _extract_head_weights( + usa_state_dict: Dict[str, torch.Tensor], + layer_idx: int, + head_idx: int, + num_mlp_layers: int, + query_matrices_per_layer: List[List[torch.Tensor]], + query_biases_per_layer: List[List[torch.Tensor]], + key_matrices_per_layer: List[List[torch.Tensor]], + key_biases_per_layer: List[List[torch.Tensor]], +) -> None: + """Extract weights for a single attention head. + + Args: + usa_state_dict: USA checkpoint state dictionary. + layer_idx: Index of the current layer. + head_idx: Index of the current attention head. + num_mlp_layers: Number of MLP layers. + query_matrices_per_layer: Storage for query weight matrices. + query_biases_per_layer: Storage for query bias vectors. + key_matrices_per_layer: Storage for key weight matrices. + key_biases_per_layer: Storage for key bias vectors. + """ + query_prefix = f"{layer_idx}.learning_to_hash_transformation_q.{head_idx}" + key_prefix = f"{layer_idx}.learning_to_hash_transformation_k.{head_idx}" + + # Extract weights from MLP layers (linear layers at indices 0, 2, 4, ...) + linear_indices = [i * 2 for i in range(num_mlp_layers)] + + for i, linear_idx in enumerate(linear_indices): + _extract_query_weights( + usa_state_dict, query_prefix, linear_idx, i, + query_matrices_per_layer, query_biases_per_layer + ) + _extract_key_weights( + usa_state_dict, key_prefix, linear_idx, i, + key_matrices_per_layer, key_biases_per_layer + ) + + +def _extract_query_weights( + usa_state_dict: Dict[str, torch.Tensor], + query_prefix: str, + linear_idx: int, + mlp_layer_idx: int, + query_matrices_per_layer: List[List[torch.Tensor]], + query_biases_per_layer: List[List[torch.Tensor]], +) -> None: + """Extract query weights for a specific MLP layer. + + Args: + usa_state_dict: USA checkpoint state dictionary. + query_prefix: Prefix for query weight keys. + linear_idx: Index of the linear layer. + mlp_layer_idx: Index of the MLP layer. + query_matrices_per_layer: Storage for query weight matrices. + query_biases_per_layer: Storage for query bias vectors. + """ + weight_key = f"{query_prefix}.{linear_idx}.weight" + bias_key = f"{query_prefix}.{linear_idx}.bias" + + if weight_key in usa_state_dict: + # Transpose to (in_features, out_features) + weight = usa_state_dict[weight_key].t() + query_matrices_per_layer[mlp_layer_idx].append(weight) + + if bias_key in usa_state_dict: + query_biases_per_layer[mlp_layer_idx].append(usa_state_dict[bias_key]) + else: + # Create zero bias if not present + zero_bias = torch.zeros(usa_state_dict[weight_key].shape[0]) + query_biases_per_layer[mlp_layer_idx].append(zero_bias) + + +def _extract_key_weights( + usa_state_dict: Dict[str, torch.Tensor], + key_prefix: str, + linear_idx: int, + mlp_layer_idx: int, + key_matrices_per_layer: List[List[torch.Tensor]], + key_biases_per_layer: List[List[torch.Tensor]], +) -> None: + """Extract key weights for a specific MLP layer. + + Args: + usa_state_dict: USA checkpoint state dictionary. + key_prefix: Prefix for key weight keys. + linear_idx: Index of the linear layer. + mlp_layer_idx: Index of the MLP layer. + key_matrices_per_layer: Storage for key weight matrices. + key_biases_per_layer: Storage for key bias vectors. + """ + weight_key = f"{key_prefix}.{linear_idx}.weight" + bias_key = f"{key_prefix}.{linear_idx}.bias" + + if weight_key in usa_state_dict: + # Transpose to (in_features, out_features) + weight = usa_state_dict[weight_key].t() + key_matrices_per_layer[mlp_layer_idx].append(weight) + + if bias_key in usa_state_dict: + key_biases_per_layer[mlp_layer_idx].append(usa_state_dict[bias_key]) + else: + # Create zero bias if not present + zero_bias = torch.zeros(usa_state_dict[weight_key].shape[0]) + key_biases_per_layer[mlp_layer_idx].append(zero_bias) + + +def _stack_head_weights( + layer_weights: Dict[str, List[torch.Tensor]], + num_mlp_layers: int, + query_matrices_per_layer: List[List[torch.Tensor]], + query_biases_per_layer: List[List[torch.Tensor]], + key_matrices_per_layer: List[List[torch.Tensor]], + key_biases_per_layer: List[List[torch.Tensor]], +) -> None: + """Stack weights from all heads for each MLP layer. + + Args: + layer_weights: Dictionary to store the stacked weights. + num_mlp_layers: Number of MLP layers. + query_matrices_per_layer: Query weight matrices for all heads. + query_biases_per_layer: Query bias vectors for all heads. + key_matrices_per_layer: Key weight matrices for all heads. + key_biases_per_layer: Key bias vectors for all heads. + """ + for i in range(num_mlp_layers): + if query_matrices_per_layer[i]: + layer_weights["query_matrix"].append( + torch.stack(query_matrices_per_layer[i]) + ) + layer_weights["query_bias"].append( + torch.stack(query_biases_per_layer[i]) + ) + layer_weights["key_matrix"].append( + torch.stack(key_matrices_per_layer[i]) + ) + layer_weights["key_bias"].append( + torch.stack(key_biases_per_layer[i]) + ) + + def create_hat_weights_file_from_usa( usa_checkpoint_path: str, target_hat_path: str, @@ -116,19 +254,21 @@ def create_hat_weights_file_from_usa( num_mlp_layers: int = 3, device: str = "cpu", ) -> None: - """Create HAT weights file from USA checkpoint. + """Create HashAttention weights file from USA checkpoint. + + This function converts USA checkpoint weights to HashAttention format + and saves them as a pickle file for later use. Args: - usa_checkpoint_path: Path to USA checkpoint file - target_hat_path: Path where HAT weights file will be saved - num_layers: Number of layers in the model - num_heads: Number of attention heads - num_mlp_layers: Number of MLP layers - device: Device to load weights on + usa_checkpoint_path: Path to the input USA checkpoint file. + target_hat_path: Path where the HashAttention weights file will be saved. + num_layers: Number of transformer layers in the model. Defaults to 32. + num_heads: Number of attention heads per layer. Defaults to 32. + num_mlp_layers: Number of MLP layers in the hash transformation. Defaults to 3. + device: Device to load the weights on ("cpu", "cuda", etc.). Defaults to "cpu". """ print("Creating HAT weights file from USA checkpoint...") - # Convert USA weights to HAT format hat_weights = convert_usa_weights_to_hash_attention( usa_checkpoint_path=usa_checkpoint_path, num_layers=num_layers, @@ -137,34 +277,72 @@ def create_hat_weights_file_from_usa( device=device, ) - # Save to pickle file - with open(target_hat_path, "wb") as f: - pickle.dump(hat_weights, f) - + _save_weights_to_file(hat_weights, target_hat_path) print(f"โœ… HAT weights saved to {target_hat_path}") +def _save_weights_to_file( + hat_weights: Dict[int, Dict[str, List[torch.Tensor]]], + target_path: str +) -> None: + """Save HashAttention weights to a pickle file. + + Args: + hat_weights: Dictionary of HashAttention weights to save. + target_path: Path where the weights file will be saved. + """ + with open(target_path, "wb") as f: + pickle.dump(hat_weights, f) + + def load_hat_weights( hat_weights_path: str, device: str = "cpu" ) -> Dict[int, Dict[str, List[torch.Tensor]]]: - """Load HAT weights from pickle file. + """Load HashAttention weights from a pickle file. + + This function loads previously saved HashAttention weights and moves + them to the specified device. Args: - hat_weights_path: Path to HAT weights pickle file - device: Device to load weights on + hat_weights_path: Path to the HashAttention weights pickle file. + device: Device to move the loaded weights to ("cpu", "cuda", etc.). Defaults to "cpu". Returns: - Dictionary of layer-wise weights in HashAttention format + Dictionary mapping layer indices to their corresponding weights in HashAttention format. + Each layer contains "query_matrix", "query_bias", "key_matrix", and "key_bias" lists. """ print(f"Loading HAT weights from {hat_weights_path}") - with open(hat_weights_path, "rb") as f: - hat_weights = pickle.load(f) - - # Move weights to specified device - for layer_idx, layer_weights in hat_weights.items(): - for key, value in layer_weights.items(): - hat_weights[layer_idx][key] = [tensor.to(device) for tensor in value] + hat_weights = _load_weights_from_file(hat_weights_path) + _move_weights_to_device(hat_weights, device) print(f"โœ… Loaded HAT weights for {len(hat_weights)} layers") return hat_weights + + +def _load_weights_from_file(file_path: str) -> Dict[int, Dict[str, List[torch.Tensor]]]: + """Load weights from a pickle file. + + Args: + file_path: Path to the pickle file. + + Returns: + Dictionary of loaded weights. + """ + with open(file_path, "rb") as f: + return pickle.load(f) + + +def _move_weights_to_device( + hat_weights: Dict[int, Dict[str, List[torch.Tensor]]], + device: str +) -> None: + """Move all weights to the specified device. + + Args: + hat_weights: Dictionary of HashAttention weights to move. + device: Target device for the weights. + """ + for layer_idx, layer_weights in hat_weights.items(): + for key, tensor_list in layer_weights.items(): + hat_weights[layer_idx][key] = [tensor.to(device) for tensor in tensor_list] From 76343ec033a96063a274a0e159c29e7d169151d2 Mon Sep 17 00:00:00 2001 From: Luis Gaspar Schroeder Date: Wed, 3 Sep 2025 10:13:23 +0200 Subject: [PATCH 4/4] Black formatting --- benchmark/AIME2024/__init__.py | 2 +- benchmark/AIME2024/aime2024.py | 34 +- benchmark/AIME2024/calculate_metrics.py | 133 ++-- .../AIME2024/create_huggingface_dataset.py | 38 +- benchmark/AIME2024/test_aime2024.py | 102 +-- benchmark/AIME2025/__init__.py | 2 +- benchmark/AIME2025/aime2025.py | 36 +- benchmark/AIME2025/calculate_metrics.py | 96 +-- .../AIME2025/create_huggingface_dataset.py | 56 +- benchmark/AIME2025/example_usage.py | 84 +-- benchmark/AIME2025/test_aime2025.py | 106 +-- benchmark/base.py | 122 ++-- benchmark/benchmark_registry.py | 88 +-- benchmark/executor.py | 601 +++++++++++------- benchmark/executor_config.py | 172 ++--- benchmark/infinite_bench/__init__.py | 2 +- benchmark/infinite_bench/calculate_metrics.py | 4 +- .../create_huggingface_dataset.py | 15 +- benchmark/infinite_bench/infinite_bench.py | 40 +- benchmark/longbench/__init__.py | 2 +- benchmark/longbench/calculate_metrics.py | 14 +- .../longbench/create_huggingface_dataset.py | 40 +- benchmark/longbench/longbench.py | 99 ++- benchmark/longbenchv2/__init__.py | 2 +- benchmark/longbenchv2/calculate_metrics.py | 4 +- .../longbenchv2/create_huggingface_dataset.py | 4 +- benchmark/longbenchv2/longbenchv2.py | 43 +- benchmark/loogle/calculate_metrics.py | 28 +- .../loogle/create_huggingface_dataset.py | 19 +- benchmark/loogle/loogle.py | 34 +- benchmark/mock_benchmark/__init__.py | 4 +- benchmark/mock_benchmark/mock_benchmark.py | 82 +-- benchmark/ruler/calculate_metrics.py | 16 +- benchmark/ruler/create_huggingface_dataset.py | 20 +- benchmark/ruler/ruler.py | 55 +- benchmark/scripts/benchmark.py | 98 ++- benchmark/scripts/executor_example.py | 202 +++--- .../full_benchmarking/full_benchmark.py | 8 +- .../generate_results_table.py | 167 ++--- .../analyse_stress_tests.py | 194 +++--- .../plot_stress_test_results.py | 414 ++++++------ .../stress_tests_adaptive_matrix.py | 440 +++++++++---- .../scripts/single_benchmark_model_example.py | 60 +- benchmark/utils/__init__.py | 18 +- benchmark/utils/data.py | 44 +- benchmark/utils/gpu.py | 99 +-- benchmark/utils/paths.py | 123 ++-- .../create_huggingface_dataset.py | 8 +- benchmark/zero_scrolls/zero_scrolls.py | 61 +- .../plans/sample_benchmark_configs.py | 55 +- sparse_attention_hub/metric_logging/logger.py | 105 +-- sparse_attention_hub/plotting/generator.py | 78 +-- .../efficient_attention/base.py | 20 +- .../research_attention/base.py | 46 +- .../implementations/random_sampling.py | 4 +- .../utils/hashattention_utils.py | 56 +- .../sparse_attention/utils/kv_utils.py | 1 + tests/integration/test_adapter_integration.py | 30 +- tests/integration/test_benchmark.py | 9 +- .../model_servers/test_huggingface.py | 6 +- tests/unit/adapters/test_adapters.py | 39 +- tests/unit/benchmark/test_longbench.py | 2 +- .../test_hashattention_top_k.py | 1 + .../test_configs_and_factories.py | 1 + .../utils/test_mask_attention_utils.py | 1 - .../py_examples/02_streaming_llm_demo_hf.py | 50 +- .../py_examples/02_streaming_llm_tutorial.py | 34 +- .../py_examples/03_hashattention_demo.py | 135 ++-- .../04_simple_benchmark_example.py | 73 ++- .../04_streaming_llm_benchmark_demo.py | 361 ++++++----- .../05_local_sink_oracle_adaptive_demo.py | 109 ++-- 71 files changed, 3125 insertions(+), 2226 deletions(-) diff --git a/benchmark/AIME2024/__init__.py b/benchmark/AIME2024/__init__.py index bb567237..58102847 100644 --- a/benchmark/AIME2024/__init__.py +++ b/benchmark/AIME2024/__init__.py @@ -8,4 +8,4 @@ from .calculate_metrics import calculate_metrics from .aime2024 import AIME2024 -__all__ = ["calculate_metrics", "AIME2024"] \ No newline at end of file +__all__ = ["calculate_metrics", "AIME2024"] diff --git a/benchmark/AIME2024/aime2024.py b/benchmark/AIME2024/aime2024.py index 8ffc779c..c068813c 100644 --- a/benchmark/AIME2024/aime2024.py +++ b/benchmark/AIME2024/aime2024.py @@ -29,22 +29,23 @@ class AIME2024(Benchmark): # AIME2024 has a single dataset all_datasets: List[str] = ["aime2024"] - + benchmark_name: str = "aime2024" huggingface_dataset_id: str = "xAlg-AI/att-hub-aime2024" def _load_datasets(self) -> pd.DataFrame: """Load AIME2024 dataset. - + AIME2024 uses a single dataset with all problems. - + Returns: pandas DataFrame with all AIME2024 problems. """ print(f"Loading AIME2024 dataset") - + try: from datasets import load_dataset + dataset = load_dataset(self.huggingface_dataset_id, split="test") df = dataset.to_pandas() df["task"] = "aime2024" # Ensure task column exists @@ -72,7 +73,7 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: # Use the calculate_metrics function from HashAttention evaluation metrics: Dict[str, Any] = calculate_metrics(results_df) - + # Format the results for consistency with other benchmarks overall_metrics: Dict[str, Any] = { "overall_score": round(metrics["accuracy"], 4), @@ -84,16 +85,19 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: "task_scores": { "aime2024": { "accuracy": round(metrics["accuracy"], 4), - "extraction_success_rate": round(metrics["extraction_success_rate"], 4) + "extraction_success_rate": round( + metrics["extraction_success_rate"], 4 + ), } }, - "summary": { - "total_tasks": 1, - "total_samples": len(results_df) - } + "summary": {"total_tasks": 1, "total_samples": len(results_df)}, } - - print(f" โœ“ AIME2024 Accuracy: {metrics['accuracy']:.3f} ({metrics['accuracy']*100:.1f}%)") - print(f" โœ“ Extraction Success Rate: {metrics['extraction_success_rate']:.3f} ({metrics['extraction_success_rate']*100:.1f}%)") - - return overall_metrics \ No newline at end of file + + print( + f" โœ“ AIME2024 Accuracy: {metrics['accuracy']:.3f} ({metrics['accuracy']*100:.1f}%)" + ) + print( + f" โœ“ Extraction Success Rate: {metrics['extraction_success_rate']:.3f} ({metrics['extraction_success_rate']*100:.1f}%)" + ) + + return overall_metrics diff --git a/benchmark/AIME2024/calculate_metrics.py b/benchmark/AIME2024/calculate_metrics.py index 6f9270cf..7f882a6c 100644 --- a/benchmark/AIME2024/calculate_metrics.py +++ b/benchmark/AIME2024/calculate_metrics.py @@ -5,51 +5,53 @@ import pandas as pd from typing import List, Dict, Any + def extract_boxed_answer(text: str) -> str: """ Extract the answer from \boxed{...} format in the text. - + Args: text: The model's response text - + Returns: The extracted answer as a string, or empty string if not found """ # Look for \boxed{...} pattern - boxed_pattern = r'\\boxed\{([^}]*)\}' + boxed_pattern = r"\\boxed\{([^}]*)\}" matches = re.findall(boxed_pattern, text) - + if matches: # Take the last boxed answer in case there are multiple answer = matches[-1].strip() - + # Extract just the number if there's additional formatting # Handle cases like "033", "23", "$23$", etc. - number_match = re.search(r'\d+', answer) + number_match = re.search(r"\d+", answer) if number_match: return number_match.group() else: return answer - + # Fallback: look for numbers at the end of the text # This handles cases where the model doesn't use \boxed format - lines = text.strip().split('\n') + lines = text.strip().split("\n") for line in reversed(lines): if line.strip(): # Look for a number in the last non-empty line - number_match = re.search(r'\b(\d{1,3})\b', line) + number_match = re.search(r"\b(\d{1,3})\b", line) if number_match: return number_match.group(1) - + return "" + def normalize_answer(answer: str) -> str: """ Normalize an answer to a standard format. - + Args: answer: The answer string to normalize - + Returns: Normalized answer string """ @@ -59,34 +61,37 @@ def normalize_answer(answer: str) -> str: return str(int(answer)) return answer + def calculate_metrics(df: pd.DataFrame) -> Dict[str, Any]: """ Calculate evaluation metrics for AIME2024 benchmark. - + Args: df: DataFrame with columns 'answer' (ground truth) and 'predicted_answer' (model output) - + Returns: Dictionary containing evaluation metrics """ - if 'predicted_answer' not in df.columns: + if "predicted_answer" not in df.columns: raise ValueError("DataFrame must contain 'predicted_answer' column") - if 'answer' not in df.columns: + if "answer" not in df.columns: raise ValueError("DataFrame must contain 'answer' column") - + total_problems = len(df) correct_answers = 0 extraction_failures = 0 - + detailed_results = [] - + for idx, row in df.iterrows(): - ground_truth = normalize_answer(str(row['answer'])) - predicted_text = str(row['predicted_answer']) if pd.notna(row['predicted_answer']) else "" - + ground_truth = normalize_answer(str(row["answer"])) + predicted_text = ( + str(row["predicted_answer"]) if pd.notna(row["predicted_answer"]) else "" + ) + # Extract the predicted answer extracted_answer = extract_boxed_answer(predicted_text) - + if not extracted_answer: extraction_failures += 1 is_correct = False @@ -95,35 +100,42 @@ def calculate_metrics(df: pd.DataFrame) -> Dict[str, Any]: is_correct = extracted_answer == ground_truth if is_correct: correct_answers += 1 - - detailed_results.append({ - 'id': row.get('id', f'problem_{idx}'), - 'ground_truth': ground_truth, - 'predicted_text': predicted_text, - 'extracted_answer': extracted_answer, - 'is_correct': is_correct, - 'extraction_failed': not bool(extracted_answer) - }) - + + detailed_results.append( + { + "id": row.get("id", f"problem_{idx}"), + "ground_truth": ground_truth, + "predicted_text": predicted_text, + "extracted_answer": extracted_answer, + "is_correct": is_correct, + "extraction_failed": not bool(extracted_answer), + } + ) + # Calculate metrics accuracy = correct_answers / total_problems if total_problems > 0 else 0.0 - extraction_success_rate = (total_problems - extraction_failures) / total_problems if total_problems > 0 else 0.0 - + extraction_success_rate = ( + (total_problems - extraction_failures) / total_problems + if total_problems > 0 + else 0.0 + ) + metrics = { - 'accuracy': accuracy, - 'correct_answers': correct_answers, - 'total_problems': total_problems, - 'extraction_success_rate': extraction_success_rate, - 'extraction_failures': extraction_failures, - 'detailed_results': detailed_results + "accuracy": accuracy, + "correct_answers": correct_answers, + "total_problems": total_problems, + "extraction_success_rate": extraction_success_rate, + "extraction_failures": extraction_failures, + "detailed_results": detailed_results, } - + return metrics + def print_metrics_summary(metrics: Dict[str, Any]) -> None: """ Print a formatted summary of the evaluation metrics. - + Args: metrics: Dictionary containing evaluation metrics """ @@ -132,34 +144,39 @@ def print_metrics_summary(metrics: Dict[str, Any]) -> None: print(f"Total Problems: {metrics['total_problems']}") print(f"Correct Answers: {metrics['correct_answers']}") print(f"Accuracy: {metrics['accuracy']:.3f} ({metrics['accuracy']*100:.1f}%)") - print(f"Extraction Success Rate: {metrics['extraction_success_rate']:.3f} ({metrics['extraction_success_rate']*100:.1f}%)") + print( + f"Extraction Success Rate: {metrics['extraction_success_rate']:.3f} ({metrics['extraction_success_rate']*100:.1f}%)" + ) print(f"Extraction Failures: {metrics['extraction_failures']}") - - if metrics['extraction_failures'] > 0: - print(f"\nNote: {metrics['extraction_failures']} problems had answer extraction failures.") + + if metrics["extraction_failures"] > 0: + print( + f"\nNote: {metrics['extraction_failures']} problems had answer extraction failures." + ) print("These are counted as incorrect answers.") + if __name__ == "__main__": # Test the metrics calculation test_data = { - 'answer': ['23', '33', '156', '902'], - 'predicted_answer': [ - 'The answer is \\boxed{23}.', - 'After solving, we get \\boxed{033}.', - 'Therefore, the answer is \\boxed{156}.', - 'The final answer is 902.' # Test fallback extraction + "answer": ["23", "33", "156", "902"], + "predicted_answer": [ + "The answer is \\boxed{23}.", + "After solving, we get \\boxed{033}.", + "Therefore, the answer is \\boxed{156}.", + "The final answer is 902.", # Test fallback extraction ], - 'id': ['2024-I-1', '2024-I-2', '2024-I-3', '2024-I-4'] + "id": ["2024-I-1", "2024-I-2", "2024-I-3", "2024-I-4"], } - + test_df = pd.DataFrame(test_data) metrics = calculate_metrics(test_df) print_metrics_summary(metrics) - + print("\nDetailed Results:") - for result in metrics['detailed_results']: + for result in metrics["detailed_results"]: print(f"ID: {result['id']}") print(f" Ground Truth: {result['ground_truth']}") print(f" Extracted: {result['extracted_answer']}") print(f" Correct: {result['is_correct']}") - print() \ No newline at end of file + print() diff --git a/benchmark/AIME2024/create_huggingface_dataset.py b/benchmark/AIME2024/create_huggingface_dataset.py index 0a419581..5f470c23 100644 --- a/benchmark/AIME2024/create_huggingface_dataset.py +++ b/benchmark/AIME2024/create_huggingface_dataset.py @@ -21,6 +21,7 @@ which is standard in mathematical competition contexts. """ + def create_aime2024_dataset(): """ Process the AIME2024 dataset and convert it to the standardized benchmark format. @@ -28,10 +29,10 @@ def create_aime2024_dataset(): # Load the original dataset dataset = load_dataset("Maxwell-Jia/AIME_2024") df = dataset["train"].to_pandas() - + # Create the standardized format processed_data = [] - + for _, row in df.iterrows(): # Format the problem with clear instructions about the boxed answer format context = f"""Solve the following AIME (American Invitational Mathematics Examination) problem. @@ -41,26 +42,29 @@ def create_aime2024_dataset(): Instructions: - The answer should be an integer between 0 and 999 - Please reason step by step, and put your final answer within \\boxed{{...}} format""" - + question = "What is the answer to this problem?" - + # The answer prefix encourages the model to show work before the final answer answer_prefix = "" - - processed_data.append({ - 'context': context, - 'question': question, - 'answer_prefix': answer_prefix, - 'answer': str(row['Answer']), # Convert to string for consistency - 'id': row['ID'], - 'max_new_tokens': 32000, # Allow comprehensive step-by-step solutions - }) - + + processed_data.append( + { + "context": context, + "question": question, + "answer_prefix": answer_prefix, + "answer": str(row["Answer"]), # Convert to string for consistency + "id": row["ID"], + "max_new_tokens": 32000, # Allow comprehensive step-by-step solutions + } + ) + # Convert to Dataset processed_dataset = Dataset.from_pandas(pd.DataFrame(processed_data)) - + return processed_dataset + if __name__ == "__main__": # Test the dataset creation processed_dataset = create_aime2024_dataset() @@ -68,4 +72,6 @@ def create_aime2024_dataset(): print("\nFirst example:") print(processed_dataset[0]) - processed_dataset.push_to_hub("xAlg-AI/att-hub-aime2024", config_name=f"aime2024", split="test") + processed_dataset.push_to_hub( + "xAlg-AI/att-hub-aime2024", config_name=f"aime2024", split="test" + ) diff --git a/benchmark/AIME2024/test_aime2024.py b/benchmark/AIME2024/test_aime2024.py index 5e42c3fe..90c77ee6 100644 --- a/benchmark/AIME2024/test_aime2024.py +++ b/benchmark/AIME2024/test_aime2024.py @@ -11,29 +11,38 @@ import sys import os + sys.path.append(os.path.dirname(os.path.abspath(__file__))) from create_huggingface_dataset import create_aime2024_dataset from calculate_metrics import calculate_metrics, print_metrics_summary import pandas as pd + def test_dataset_creation(): """Test that the dataset can be created successfully.""" print("Testing AIME2024 dataset creation...") - + dataset = create_aime2024_dataset() - + print(f"โœ“ Dataset created successfully with {len(dataset)} problems") - + # Verify dataset structure - required_keys = ['context', 'question', 'answer_prefix', 'answer', 'id', 'max_new_tokens'] + required_keys = [ + "context", + "question", + "answer_prefix", + "answer", + "id", + "max_new_tokens", + ] first_example = dataset[0] - + for key in required_keys: assert key in first_example, f"Missing required key: {key}" - + print("โœ“ Dataset structure is correct") - + # Show some examples print(f"\nSample problems:") for i in range(min(3, len(dataset))): @@ -42,99 +51,114 @@ def test_dataset_creation(): print(f" Answer: {example['answer']}") print(f" Problem preview: {example['context'][:100]}...") print() - + return dataset + def test_metrics_calculation(): """Test the metrics calculation with sample data.""" print("Testing AIME2024 metrics calculation...") - + # Create test data with various scenarios test_data = { - 'answer': ['23', '33', '156', '902', '45'], - 'predicted_answer': [ - 'The answer is \\boxed{23}.', # Correct with boxed format - 'After solving, we get \\boxed{033}.', # Correct with leading zeros - 'Therefore, the answer is \\boxed{156}.', # Correct - 'The final answer is 902.', # Correct without boxed format - 'I think the answer is \\boxed{44}.' # Incorrect + "answer": ["23", "33", "156", "902", "45"], + "predicted_answer": [ + "The answer is \\boxed{23}.", # Correct with boxed format + "After solving, we get \\boxed{033}.", # Correct with leading zeros + "Therefore, the answer is \\boxed{156}.", # Correct + "The final answer is 902.", # Correct without boxed format + "I think the answer is \\boxed{44}.", # Incorrect ], - 'id': ['2024-I-1', '2024-I-2', '2024-I-3', '2024-I-4', '2024-I-5'] + "id": ["2024-I-1", "2024-I-2", "2024-I-3", "2024-I-4", "2024-I-5"], } - + test_df = pd.DataFrame(test_data) metrics = calculate_metrics(test_df) - + print_metrics_summary(metrics) - + # Verify expected results - assert metrics['total_problems'] == 5, f"Expected 5 problems, got {metrics['total_problems']}" - assert metrics['correct_answers'] == 4, f"Expected 4 correct answers, got {metrics['correct_answers']}" - assert metrics['accuracy'] == 0.8, f"Expected accuracy 0.8, got {metrics['accuracy']}" - assert metrics['extraction_failures'] == 0, f"Expected 0 extraction failures, got {metrics['extraction_failures']}" - + assert ( + metrics["total_problems"] == 5 + ), f"Expected 5 problems, got {metrics['total_problems']}" + assert ( + metrics["correct_answers"] == 4 + ), f"Expected 4 correct answers, got {metrics['correct_answers']}" + assert ( + metrics["accuracy"] == 0.8 + ), f"Expected accuracy 0.8, got {metrics['accuracy']}" + assert ( + metrics["extraction_failures"] == 0 + ), f"Expected 0 extraction failures, got {metrics['extraction_failures']}" + print("โœ“ Metrics calculation is correct") - + return metrics + def test_integration(): """Test integration with the main evaluation system.""" print("Testing AIME2024 integration...") - + # Test that the dataset can be imported and used try: - sys.path.append('..') + sys.path.append("..") from AIME2024.calculate_metrics import calculate_metrics from AIME2024.create_huggingface_dataset import create_aime2024_dataset - + # Test dataset creation through import dataset = create_aime2024_dataset() print(f"โœ“ Integration test passed - dataset has {len(dataset)} examples") - + # Verify the dataset can be converted to pandas df = dataset.to_pandas() print(f"โœ“ Dataset conversion to pandas successful - shape: {df.shape}") - + return True - + except Exception as e: print(f"โœ— Integration test failed: {e}") return False + def main(): """Run all tests for AIME2024 benchmark.""" print("AIME2024 Benchmark Test Suite") print("=" * 50) - + try: # Test dataset creation dataset = test_dataset_creation() print() - + # Test metrics calculation metrics = test_metrics_calculation() print() - + # Test integration integration_success = test_integration() print() - + if integration_success: print("๐ŸŽ‰ All tests passed! AIME2024 benchmark is ready to use.") print() print("Usage examples:") print(" cd evaluation") - print(" python evaluate.py --dataset aime2024 --base_model meta-llama/Llama-3.1-8B-Instruct --device cpu") + print( + " python evaluate.py --dataset aime2024 --base_model meta-llama/Llama-3.1-8B-Instruct --device cpu" + ) print(" python evaluate.py --dataset aime2024 --device 1 --num_samples 10") else: print("โŒ Some tests failed. Please check the implementation.") sys.exit(1) - + except Exception as e: print(f"โŒ Test suite failed with error: {e}") import traceback + traceback.print_exc() sys.exit(1) + if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/benchmark/AIME2025/__init__.py b/benchmark/AIME2025/__init__.py index b5a69b8d..01b7ec84 100644 --- a/benchmark/AIME2025/__init__.py +++ b/benchmark/AIME2025/__init__.py @@ -8,4 +8,4 @@ from .calculate_metrics import calculate_metrics from .aime2025 import AIME2025 -__all__ = ["calculate_metrics", "AIME2025"] \ No newline at end of file +__all__ = ["calculate_metrics", "AIME2025"] diff --git a/benchmark/AIME2025/aime2025.py b/benchmark/AIME2025/aime2025.py index 5eebe349..02101668 100644 --- a/benchmark/AIME2025/aime2025.py +++ b/benchmark/AIME2025/aime2025.py @@ -29,22 +29,23 @@ class AIME2025(Benchmark): # AIME2025 has a single dataset all_datasets: List[str] = ["aime2025"] - + benchmark_name: str = "aime2025" huggingface_dataset_id: str = "xAlg-AI/att-hub-aime2025" def _load_datasets(self) -> pd.DataFrame: """Load AIME2025 dataset. - + AIME2025 uses a single dataset with all problems. - + Returns: pandas DataFrame with all AIME2025 problems. """ print(f"Loading AIME2025 dataset") - + try: from datasets import load_dataset + dataset = load_dataset(self.huggingface_dataset_id, split="test") df = dataset.to_pandas() df["task"] = "aime2025" # Ensure task column exists @@ -72,7 +73,7 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: # Use the calculate_metrics function from HashAttention evaluation metrics: Dict[str, Any] = calculate_metrics(results_df) - + # Format the results for consistency with other benchmarks overall_metrics: Dict[str, Any] = { "overall_score": round(metrics["exact_match"], 4), @@ -84,17 +85,20 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: "aime2025": { "exact_match": round(metrics["exact_match"], 4), "extraction_rate": round(metrics["extraction_rate"], 4), - "boxed_format_rate": round(metrics["boxed_format_rate"], 4) + "boxed_format_rate": round(metrics["boxed_format_rate"], 4), } }, - "summary": { - "total_tasks": 1, - "total_samples": len(results_df) - } + "summary": {"total_tasks": 1, "total_samples": len(results_df)}, } - - print(f" โœ“ AIME2025 Exact Match: {metrics['exact_match']:.3f} ({metrics['exact_match']*100:.1f}%)") - print(f" โœ“ Extraction Rate: {metrics['extraction_rate']:.3f} ({metrics['extraction_rate']*100:.1f}%)") - print(f" โœ“ Boxed Format Rate: {metrics['boxed_format_rate']:.3f} ({metrics['boxed_format_rate']*100:.1f}%)") - - return overall_metrics \ No newline at end of file + + print( + f" โœ“ AIME2025 Exact Match: {metrics['exact_match']:.3f} ({metrics['exact_match']*100:.1f}%)" + ) + print( + f" โœ“ Extraction Rate: {metrics['extraction_rate']:.3f} ({metrics['extraction_rate']*100:.1f}%)" + ) + print( + f" โœ“ Boxed Format Rate: {metrics['boxed_format_rate']:.3f} ({metrics['boxed_format_rate']*100:.1f}%)" + ) + + return overall_metrics diff --git a/benchmark/AIME2025/calculate_metrics.py b/benchmark/AIME2025/calculate_metrics.py index 8dcb6217..0c0b1fbd 100644 --- a/benchmark/AIME2025/calculate_metrics.py +++ b/benchmark/AIME2025/calculate_metrics.py @@ -10,38 +10,38 @@ def extract_boxed_answer(text: str) -> str: """ Extract the answer from \boxed{...} format in the text. - + Args: text: The model's response text - + Returns: The extracted answer as a string, or empty string if not found """ # Look for \boxed{...} pattern - boxed_pattern = r'\\boxed\{([^}]*)\}' + boxed_pattern = r"\\boxed\{([^}]*)\}" matches = re.findall(boxed_pattern, text) - + if matches: # Return the last boxed answer found (in case there are multiple) return matches[-1].strip() - + # Fallback: look for boxed without backslash (in case the model omits it) - boxed_pattern_alt = r'boxed\{([^}]*)\}' + boxed_pattern_alt = r"boxed\{([^}]*)\}" matches = re.findall(boxed_pattern_alt, text) - + if matches: return matches[-1].strip() - + return "" def extract_numerical_answer(text: str) -> str: """ Extract a numerical answer from text, with fallback strategies. - + Args: text: The text to extract from - + Returns: The extracted numerical answer as a string """ @@ -49,17 +49,17 @@ def extract_numerical_answer(text: str) -> str: boxed_answer = extract_boxed_answer(text) if boxed_answer: # Extract just the number from the boxed content - numbers = re.findall(r'\d+', boxed_answer) + numbers = re.findall(r"\d+", boxed_answer) if numbers: return numbers[-1] # Take the last number found - + # Fallback 1: Look for "answer is X" or "answer: X" patterns answer_patterns = [ - r'(?:answer|solution)\s*(?:is|:)\s*(\d+)', - r'(?:the\s+)?answer\s*(?:is|:)\s*(\d+)', - r'(?:therefore|thus|so)\s*(?:the\s+)?(?:answer|solution)\s*(?:is|:)\s*(\d+)', + r"(?:answer|solution)\s*(?:is|:)\s*(\d+)", + r"(?:the\s+)?answer\s*(?:is|:)\s*(\d+)", + r"(?:therefore|thus|so)\s*(?:the\s+)?(?:answer|solution)\s*(?:is|:)\s*(\d+)", ] - + for pattern in answer_patterns: matches = re.findall(pattern, text, re.IGNORECASE) if matches: @@ -67,125 +67,127 @@ def extract_numerical_answer(text: str) -> str: num = int(matches[-1]) if 0 <= num <= 999: return matches[-1] - + # Fallback 2: Look for numbers at the end of the text # This catches cases where the model just states the number - lines = text.strip().split('\n') + lines = text.strip().split("\n") for line in reversed(lines): line = line.strip() if line: - numbers = re.findall(r'\b\d+\b', line) + numbers = re.findall(r"\b\d+\b", line) if numbers: # Check if the number is in valid AIME range (0-999) num = int(numbers[-1]) if 0 <= num <= 999: return str(num) - + # Fallback 3: Find any number in valid AIME range - all_numbers = re.findall(r'\b\d+\b', text) + all_numbers = re.findall(r"\b\d+\b", text) for num_str in reversed(all_numbers): # Check from end to beginning num = int(num_str) if 0 <= num <= 999: return str(num) - + return "" -def calculate_exact_match_score(predictions: List[str], references: List[List[str]]) -> float: +def calculate_exact_match_score( + predictions: List[str], references: List[List[str]] +) -> float: """ Calculate exact match accuracy between predictions and references. - + Args: predictions: List of predicted answers references: List of reference answers (each can have multiple valid answers) - + Returns: Exact match accuracy as a float between 0 and 1 """ correct = 0 total = len(predictions) - + for pred, ref_list in zip(predictions, references): # Extract numerical answer from prediction pred_answer = extract_numerical_answer(pred) - + # Check if prediction matches any of the reference answers if pred_answer in ref_list: correct += 1 - + return correct / total if total > 0 else 0.0 def calculate_metrics(df: pd.DataFrame) -> dict: """ Calculate metrics for the AIME2025 benchmark. - + Args: df: DataFrame with columns 'predicted_answer' and 'answer' - + Returns: Dictionary containing the calculated metrics """ predictions = df["predicted_answer"].tolist() references = df["answer"].tolist() - + # Ensure references are in the correct format (list of lists) if references and not isinstance(references[0], list): references = [[str(ref)] for ref in references] - + # Calculate exact match accuracy exact_match = calculate_exact_match_score(predictions, references) - + # Additional analysis: count how many answers were successfully extracted extracted_count = 0 boxed_count = 0 - + for pred in predictions: extracted = extract_numerical_answer(pred) if extracted: extracted_count += 1 - + # Count how many used the boxed format if extract_boxed_answer(pred): boxed_count += 1 - + extraction_rate = extracted_count / len(predictions) if predictions else 0.0 boxed_format_rate = boxed_count / len(predictions) if predictions else 0.0 - + return { "exact_match": exact_match, "extraction_rate": extraction_rate, "boxed_format_rate": boxed_format_rate, - "total_problems": len(predictions) + "total_problems": len(predictions), } def analyze_errors(df: pd.DataFrame) -> dict: """ Analyze common error patterns in the predictions. - + Args: df: DataFrame with predictions and references - + Returns: Dictionary with error analysis """ predictions = df["predicted_answer"].tolist() references = df["answer"].tolist() - + if references and not isinstance(references[0], list): references = [[str(ref)] for ref in references] - + error_types = { "no_answer_extracted": 0, "wrong_answer": 0, "out_of_range": 0, - "format_issues": 0 + "format_issues": 0, } - + for pred, ref_list in zip(predictions, references): extracted = extract_numerical_answer(pred) - + if not extracted: error_types["no_answer_extracted"] += 1 elif extracted not in ref_list: @@ -196,5 +198,5 @@ def analyze_errors(df: pd.DataFrame) -> dict: error_types["out_of_range"] += 1 except ValueError: error_types["format_issues"] += 1 - - return error_types \ No newline at end of file + + return error_types diff --git a/benchmark/AIME2025/create_huggingface_dataset.py b/benchmark/AIME2025/create_huggingface_dataset.py index b71d7d73..27a78fad 100644 --- a/benchmark/AIME2025/create_huggingface_dataset.py +++ b/benchmark/AIME2025/create_huggingface_dataset.py @@ -23,6 +23,7 @@ which is standard in mathematical competition contexts. """ + def create_aime2025_dataset(): """ Process the AIME2025 dataset and convert it to the standardized benchmark format. @@ -30,10 +31,10 @@ def create_aime2025_dataset(): # Load the original dataset dataset = load_dataset("yentinglin/aime_2025") df = dataset["train"].to_pandas() - + # Create the standardized format processed_data = [] - + for _, row in df.iterrows(): # Format the problem with clear instructions about the boxed answer format context = f"""Solve the following AIME (American Invitational Mathematics Examination) problem. @@ -43,43 +44,50 @@ def create_aime2025_dataset(): Instructions: - The answer should be an integer between 0 and 999 - You must wrap your final answer in \\boxed{{...}} format""" - + question = "What is the answer to this problem?" - + # The answer prefix encourages the model to show work before the final answer answer_prefix = "" - + # Convert answer to list format (some benchmarks expect this) - answer = [str(row['answer'])] - - processed_data.append({ - 'context': context, - 'question': question, - 'answer_prefix': answer_prefix, - 'answer': answer, - 'task': 'aime2025', - 'max_new_tokens': 32000, # Allow comprehensive step-by-step solutions - 'problem_id': row['id'], - 'year': row['year'] - }) - + answer = [str(row["answer"])] + + processed_data.append( + { + "context": context, + "question": question, + "answer_prefix": answer_prefix, + "answer": answer, + "task": "aime2025", + "max_new_tokens": 32000, # Allow comprehensive step-by-step solutions + "problem_id": row["id"], + "year": row["year"], + } + ) + # Convert to DataFrame and then to Dataset processed_df = pd.DataFrame(processed_data) - + # Select only the required columns for the benchmark - final_df = processed_df[['context', 'question', 'answer_prefix', 'answer', 'task', 'max_new_tokens']] - + final_df = processed_df[ + ["context", "question", "answer_prefix", "answer", "task", "max_new_tokens"] + ] + return Dataset.from_pandas(final_df) + if __name__ == "__main__": # Create the processed dataset processed_dataset = create_aime2025_dataset() - + # Push to hub (you would need to set up your own repo) # For now, we'll just save locally or use the existing dataset print(f"Processed {len(processed_dataset)} AIME2025 problems") print("Sample processed example:") print(processed_dataset[0]) - + # Optionally save locally for testing - processed_dataset.push_to_hub("xAlg-AI/att-hub-aime2025", config_name=f"aime2025", split="test") + processed_dataset.push_to_hub( + "xAlg-AI/att-hub-aime2025", config_name=f"aime2025", split="test" + ) diff --git a/benchmark/AIME2025/example_usage.py b/benchmark/AIME2025/example_usage.py index 5fe3d38e..952faf3f 100644 --- a/benchmark/AIME2025/example_usage.py +++ b/benchmark/AIME2025/example_usage.py @@ -8,6 +8,7 @@ import sys import os + sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from AIME2025.create_huggingface_dataset import create_aime2025_dataset @@ -19,21 +20,21 @@ def show_sample_problems(): """Display sample problems from the AIME2025 dataset.""" print("AIME2025 Sample Problems") print("=" * 50) - + dataset = create_aime2025_dataset() - + # Show first 3 problems for i in range(min(3, len(dataset))): example = dataset[i] print(f"\nProblem {i+1}:") print("-" * 30) - + # Extract just the problem statement from the context - context = example['context'] + context = example["context"] problem_start = context.find("Problem: ") + len("Problem: ") problem_end = context.find("\n\nInstructions:") problem = context[problem_start:problem_end] - + print(f"Problem: {problem}") print(f"Answer: {example['answer'][0]}") @@ -43,50 +44,51 @@ def simulate_model_responses(): print("\n" + "=" * 50) print("Simulated Model Evaluation") print("=" * 50) - + # Create some simulated model responses simulated_responses = [ { - 'predicted_answer': "Let me work through this step by step.\n\nAfter calculating the bases, I find that the sum is \\boxed{70}.", - 'answer': ['70'] # Correct + "predicted_answer": "Let me work through this step by step.\n\nAfter calculating the bases, I find that the sum is \\boxed{70}.", + "answer": ["70"], # Correct }, { - 'predicted_answer': "This is a complex problem. After working through it, the answer is \\boxed{42}.", - 'answer': ['588'] # Wrong + "predicted_answer": "This is a complex problem. After working through it, the answer is \\boxed{42}.", + "answer": ["588"], # Wrong }, { - 'predicted_answer': "The calculation gives us 588 as the final result.", - 'answer': ['588'] # Correct, but no boxed format + "predicted_answer": "The calculation gives us 588 as the final result.", + "answer": ["588"], # Correct, but no boxed format }, { - 'predicted_answer': "Answer: 16", - 'answer': ['16'] # Correct, no boxed format + "predicted_answer": "Answer: 16", + "answer": ["16"], # Correct, no boxed format }, { - 'predicted_answer': "This problem is too difficult to solve.", - 'answer': ['100'] # No answer extracted - } + "predicted_answer": "This problem is too difficult to solve.", + "answer": ["100"], # No answer extracted + }, ] - + # Create DataFrame df = pd.DataFrame(simulated_responses) - + # Calculate metrics metrics = calculate_metrics(df) - + print("Simulated Results:") print(f"Total problems: {len(simulated_responses)}") print(f"Exact match accuracy: {metrics['exact_match']:.1%}") print(f"Answer extraction rate: {metrics['extraction_rate']:.1%}") print(f"Boxed format usage: {metrics['boxed_format_rate']:.1%}") - + print("\nDetailed breakdown:") for i, response in enumerate(simulated_responses): from AIME2025.calculate_metrics import extract_numerical_answer - extracted = extract_numerical_answer(response['predicted_answer']) - correct = extracted in response['answer'] + + extracted = extract_numerical_answer(response["predicted_answer"]) + correct = extracted in response["answer"] status = "โœ“ Correct" if correct else "โœ— Wrong" - + print(f"Problem {i+1}: {status}") print(f" Expected: {response['answer'][0]}") print(f" Extracted: '{extracted}'") @@ -99,12 +101,15 @@ def show_usage_instructions(): print("=" * 50) print("Usage Instructions") print("=" * 50) - + print("\n1. Command Line Usage:") - print(" python evaluation/evaluate.py --dataset aime2025 --base_model meta-llama/Llama-3.1-8B-Instruct") - + print( + " python evaluation/evaluate.py --dataset aime2025 --base_model meta-llama/Llama-3.1-8B-Instruct" + ) + print("\n2. Programmatic Usage:") - print(""" + print( + """ from evaluation.evaluate import evaluate # Run evaluation @@ -114,10 +119,12 @@ def show_usage_instructions(): max_new_tokens=4096, num_samples=10 # Optional: evaluate on subset ) - """) - + """ + ) + print("\n3. Custom Evaluation:") - print(""" + print( + """ from evaluation.AIME2025 import create_aime2025_dataset, calculate_metrics import pandas as pd @@ -134,10 +141,12 @@ def show_usage_instructions(): }) metrics = calculate_metrics(results_df) print(metrics) - """) - + """ + ) + print("\n4. Expected Output Format:") - print(""" + print( + """ Models should respond with step-by-step reasoning and wrap the final answer in \\boxed{...} format: @@ -150,7 +159,8 @@ def show_usage_instructions(): [mathematical reasoning...] Therefore, the sum of all valid bases is \\boxed{70}." - """) + """ + ) def main(): @@ -158,11 +168,11 @@ def main(): show_sample_problems() simulate_model_responses() show_usage_instructions() - + print("\n" + "=" * 50) print("AIME2025 Benchmark Ready!") print("=" * 50) if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/benchmark/AIME2025/test_aime2025.py b/benchmark/AIME2025/test_aime2025.py index 0a9ae638..44571803 100644 --- a/benchmark/AIME2025/test_aime2025.py +++ b/benchmark/AIME2025/test_aime2025.py @@ -8,11 +8,16 @@ import sys import os + sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import pandas as pd from AIME2025.create_huggingface_dataset import create_aime2025_dataset -from AIME2025.calculate_metrics import calculate_metrics, extract_numerical_answer, analyze_errors +from AIME2025.calculate_metrics import ( + calculate_metrics, + extract_numerical_answer, + analyze_errors, +) def test_dataset_creation(): @@ -20,20 +25,27 @@ def test_dataset_creation(): print("=" * 60) print("Testing AIME2025 Dataset Creation") print("=" * 60) - + dataset = create_aime2025_dataset() print(f"โœ“ Successfully created dataset with {len(dataset)} examples") - + # Check the structure sample = dataset[0] - required_keys = ['context', 'question', 'answer_prefix', 'answer', 'task', 'max_new_tokens'] - + required_keys = [ + "context", + "question", + "answer_prefix", + "answer", + "task", + "max_new_tokens", + ] + for key in required_keys: if key in sample: print(f"โœ“ Required key '{key}' present") else: print(f"โœ— Required key '{key}' missing") - + # Show a sample print("\nSample example:") print(f"Context (first 200 chars): {sample['context'][:200]}...") @@ -41,7 +53,7 @@ def test_dataset_creation(): print(f"Answer: {sample['answer']}") print(f"Task: {sample['task']}") print(f"Max new tokens: {sample['max_new_tokens']}") - + return dataset @@ -50,7 +62,7 @@ def test_answer_extraction(): print("\n" + "=" * 60) print("Testing Answer Extraction") print("=" * 60) - + test_cases = [ ("\\boxed{42}", "42", "Standard boxed format"), ("The answer is \\boxed{123}", "123", "Boxed with prefix"), @@ -63,7 +75,7 @@ def test_answer_extraction(): ("The answer is 1000", "", "Out of range (should be empty)"), ("Multiple numbers: 42, 123, 456", "456", "Multiple numbers (last valid one)"), ] - + for input_text, expected, description in test_cases: extracted = extract_numerical_answer(input_text) status = "โœ“" if extracted == expected else "โœ—" @@ -80,48 +92,54 @@ def test_metrics_calculation(): print("=" * 60) print("Testing Metrics Calculation") print("=" * 60) - + # Create test data with known outcomes test_data = { - 'predicted_answer': [ + "predicted_answer": [ "Let me solve this step by step.\n\nThe answer is \\boxed{70}", # Correct, boxed - "After calculation, I get \\boxed{42}", # Wrong answer, boxed - "The solution is 123", # Correct, no boxed - "Answer: 999", # Correct, no boxed - "This problem is too complex to solve", # No answer - "The result is \\boxed{500}", # Correct, boxed + "After calculation, I get \\boxed{42}", # Wrong answer, boxed + "The solution is 123", # Correct, no boxed + "Answer: 999", # Correct, no boxed + "This problem is too complex to solve", # No answer + "The result is \\boxed{500}", # Correct, boxed + ], + "answer": [ + ["70"], # Match + ["123"], # No match (predicted 42) + ["123"], # Match + ["999"], # Match + ["100"], # No match (no prediction) + ["500"], # Match ], - 'answer': [ - ['70'], # Match - ['123'], # No match (predicted 42) - ['123'], # Match - ['999'], # Match - ['100'], # No match (no prediction) - ['500'], # Match - ] } - + test_df = pd.DataFrame(test_data) metrics = calculate_metrics(test_df) - + print("Calculated metrics:") for key, value in metrics.items(): print(f" {key}: {value}") - + # Expected results: # - exact_match: 4/6 = 0.667 (problems 1, 3, 4, 6 correct) # - extraction_rate: 5/6 = 0.833 (all except problem 5) # - boxed_format_rate: 3/6 = 0.5 (problems 1, 2, 6) - - expected_exact_match = 4/6 - expected_extraction_rate = 5/6 - expected_boxed_rate = 3/6 - + + expected_exact_match = 4 / 6 + expected_extraction_rate = 5 / 6 + expected_boxed_rate = 3 / 6 + print(f"\nValidation:") - print(f"โœ“ Exact match: {metrics['exact_match']:.3f} (expected: {expected_exact_match:.3f})") - print(f"โœ“ Extraction rate: {metrics['extraction_rate']:.3f} (expected: {expected_extraction_rate:.3f})") - print(f"โœ“ Boxed format rate: {metrics['boxed_format_rate']:.3f} (expected: {expected_boxed_rate:.3f})") - + print( + f"โœ“ Exact match: {metrics['exact_match']:.3f} (expected: {expected_exact_match:.3f})" + ) + print( + f"โœ“ Extraction rate: {metrics['extraction_rate']:.3f} (expected: {expected_extraction_rate:.3f})" + ) + print( + f"โœ“ Boxed format rate: {metrics['boxed_format_rate']:.3f} (expected: {expected_boxed_rate:.3f})" + ) + # Test error analysis errors = analyze_errors(test_df) print(f"\nError analysis:") @@ -134,18 +152,18 @@ def test_integration(): print("\n" + "=" * 60) print("Testing Integration") print("=" * 60) - + try: # Test that the benchmark can be imported from the main evaluation module sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - + # This would normally import from evaluate.py, but we'll skip due to dependencies print("โœ“ Integration test skipped (requires full environment)") print(" The benchmark has been properly integrated into evaluate.py") print(" - Added to DATASET_DICT as 'aime2025': 'yentinglin/aime_2025'") print(" - Added to SCORER_DICT as 'aime2025': aime2025_scorer") print(" - Added special handling for dataset processing") - + except Exception as e: print(f"โœ— Integration test failed: {e}") @@ -154,20 +172,22 @@ def main(): """Run all tests.""" print("AIME2025 Benchmark Test Suite") print("=" * 60) - + # Run all tests dataset = test_dataset_creation() test_answer_extraction() test_metrics_calculation() test_integration() - + print("\n" + "=" * 60) print("Test Suite Complete") print("=" * 60) print("The AIME2025 benchmark is ready for use!") print("\nTo run the benchmark:") - print(" python evaluation/evaluate.py --dataset aime2025 --base_model ") + print( + " python evaluation/evaluate.py --dataset aime2025 --base_model " + ) if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/benchmark/base.py b/benchmark/base.py index 2a7c3a87..bb4c90d9 100644 --- a/benchmark/base.py +++ b/benchmark/base.py @@ -40,10 +40,10 @@ class Benchmark(ABC): ... all_datasets = ["task1", "task2"] ... benchmark_name = "my_benchmark" ... huggingface_dataset_id = "my_org/my_dataset" - ... + ... ... def post_run_evaluate(self, results_df): ... return {"accuracy": 0.95} - >>> + >>> >>> benchmark = MyBenchmark(subsets_to_run=["task1"]) >>> results = benchmark.run_benchmark(adapter, result_dir="/path/to/results", generation_kwargs={"max_new_tokens": 50}, request_kwargs={"max_context_length": 1024}) """ @@ -63,11 +63,17 @@ def __init__(self, subsets_to_run: Optional[List[str]] = None) -> None: ValueError: If any subset in subsets_to_run is not in all_datasets. """ if not self.all_datasets: - raise ValueError(f"Subclass {self.__class__.__name__} must define all_datasets") + raise ValueError( + f"Subclass {self.__class__.__name__} must define all_datasets" + ) if not self.benchmark_name: - raise ValueError(f"Subclass {self.__class__.__name__} must define benchmark_name") + raise ValueError( + f"Subclass {self.__class__.__name__} must define benchmark_name" + ) if not self.huggingface_dataset_id: - raise ValueError(f"Subclass {self.__class__.__name__} must define huggingface_dataset_id") + raise ValueError( + f"Subclass {self.__class__.__name__} must define huggingface_dataset_id" + ) if subsets_to_run is None: self.subsets_to_run = self.all_datasets.copy() @@ -112,7 +118,7 @@ def _load_datasets(self) -> pd.DataFrame: # Load the full dataset dataset = load_dataset(self.huggingface_dataset_id, split="test") df: pd.DataFrame = dataset.to_pandas() - + # Filter to only include subsets we want to run if "task" in df.columns: # Filter by task column if it exists @@ -121,11 +127,13 @@ def _load_datasets(self) -> pd.DataFrame: # If no task column, assume the dataset only contains our subsets # This is a simplified assumption based on user guidance pass - + return df - + except Exception as e: - raise Exception(f"Failed to load dataset {self.huggingface_dataset_id}: {str(e)}") + raise Exception( + f"Failed to load dataset {self.huggingface_dataset_id}: {str(e)}" + ) def _validate_dataset_size(self, df: pd.DataFrame) -> None: """Validate dataset size and warn if too large. @@ -137,15 +145,15 @@ def _validate_dataset_size(self, df: pd.DataFrame) -> None: warnings.warn( f"Dataset has {len(df)} rows (>10K). Repository not expected to handle " "large datasets. If needed, request this feature.", - UserWarning + UserWarning, ) def _process_all_requests( - self, - adapter: ModelAdapter, + self, + adapter: ModelAdapter, dataset_df: pd.DataFrame, generation_kwargs: Dict[str, Any], - request_kwargs: Dict[str, Any] + request_kwargs: Dict[str, Any], ) -> pd.DataFrame: """Process all samples through the model adapter using context grouping for efficiency. @@ -164,47 +172,60 @@ def _process_all_requests( # Truncate dataset to max_requests dataset_df = dataset_df.head(max_requests) - - + # Group by context for efficiency (following HashAttention approach) df_context = dataset_df.groupby("context") - - for context, df_group in tqdm(df_context, desc="Processing contexts", total=dataset_df["context"].nunique()): + + for context, df_group in tqdm( + df_context, + desc="Processing contexts", + total=dataset_df["context"].nunique(), + ): questions: List[str] = df_group["question"].to_list() - + try: # Create request using current adapter interface (simplified) answer_prefix = df_group["answer_prefix"].iloc[0] - request: Request = Request(context=context, questions=questions, answer_prefix=answer_prefix) - + request: Request = Request( + context=context, questions=questions, answer_prefix=answer_prefix + ) + # Process through adapter - response: RequestResponse = adapter.process_request(request, generation_kwargs, request_kwargs) - + response: RequestResponse = adapter.process_request( + request, generation_kwargs, request_kwargs + ) + # Assign responses back to DataFrame if isinstance(response.responses, list): - dataset_df.loc[df_group.index, "predicted_answer"] = response.responses + dataset_df.loc[df_group.index, "predicted_answer"] = ( + response.responses + ) else: # Single response case - dataset_df.loc[df_group.index, "predicted_answer"] = [response.responses] * len(df_group) - + dataset_df.loc[df_group.index, "predicted_answer"] = [ + response.responses + ] * len(df_group) + # Memory cleanup for large contexts if torch.cuda.is_available(): torch.cuda.empty_cache() - + except Exception as e: # Log error but continue processing other contexts print(f"Error processing context (length {len(context)}): {str(e)}") # Fill with empty responses for failed contexts - dataset_df.loc[df_group.index, "predicted_answer"] = [""] * len(df_group) - + dataset_df.loc[df_group.index, "predicted_answer"] = [""] * len( + df_group + ) + return dataset_df def run_benchmark( - self, - adapter: ModelAdapter, + self, + adapter: ModelAdapter, result_dir: str, generation_kwargs: Optional[Dict[str, Any]] = None, - request_kwargs: Optional[Dict[str, Any]] = None + request_kwargs: Optional[Dict[str, Any]] = None, ) -> Dict[str, Any]: """Main orchestration method for running complete benchmark. @@ -222,54 +243,60 @@ def run_benchmark( generation_kwargs = {} if request_kwargs is None: request_kwargs = {} - + # Create result directory if it doesn't exist result_path: Path = Path(result_dir) result_path.mkdir(parents=True, exist_ok=True) - + # Load datasets print(f"Loading {self.benchmark_name} datasets: {self.subsets_to_run}") dataset_df: pd.DataFrame = self._load_datasets() print(f"Loaded {len(dataset_df)} samples") # Validate dataset size self._validate_dataset_size(dataset_df) - + # Process all requests through the adapter print("Processing requests through adapter...") - results_df: pd.DataFrame = self._process_all_requests(adapter, dataset_df, generation_kwargs, request_kwargs) - + results_df: pd.DataFrame = self._process_all_requests( + adapter, dataset_df, generation_kwargs, request_kwargs + ) + # Compute evaluation metrics print("Computing evaluation metrics...") metrics: Dict[str, Any] = self.post_run_evaluate(results_df) - + # Save results raw_results_path: Path = result_path / "raw_results.csv" save_dataframe_to_csv(results_df, str(raw_results_path), index=False) print(f"Saved raw results to {raw_results_path}") - + # Save metrics metrics_path: Path = result_path / "metrics.json" with open(metrics_path, "w") as f: json.dump(metrics, f, indent=2) print(f"Saved metrics to {metrics_path}") - + # Save configuration parameters config_path: Path = result_path / "config.json" - + config_data = { - "model_kwargs": make_serializable(getattr(adapter, 'model_kwargs', {})), - "tokenizer_kwargs": make_serializable(getattr(adapter, 'tokenizer_kwargs', {})), - "sparse_attention_config": make_serializable(getattr(adapter, 'sparse_attention_config', None)), + "model_kwargs": make_serializable(getattr(adapter, "model_kwargs", {})), + "tokenizer_kwargs": make_serializable( + getattr(adapter, "tokenizer_kwargs", {}) + ), + "sparse_attention_config": make_serializable( + getattr(adapter, "sparse_attention_config", None) + ), "generation_kwargs": make_serializable(generation_kwargs), "request_kwargs": make_serializable(request_kwargs), "benchmark_name": self.benchmark_name, "subsets_to_run": self.subsets_to_run, - "huggingface_dataset_id": self.huggingface_dataset_id + "huggingface_dataset_id": self.huggingface_dataset_id, } with open(config_path, "w") as f: json.dump(config_data, f, indent=2) print(f"Saved configuration to {config_path}") - + return metrics @abstractmethod @@ -282,7 +309,7 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: Args: results_df: DataFrame containing input data and model outputs with columns: - context: The input context - - question: The input question + - question: The input question - predicted_answer: Model's predicted answer - Plus any other columns from the original dataset @@ -290,6 +317,3 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: Dictionary containing computed metrics (e.g., {"accuracy": 0.95, "f1": 0.88}). """ pass - - - diff --git a/benchmark/benchmark_registry.py b/benchmark/benchmark_registry.py index bbc5bdf8..47d19d41 100644 --- a/benchmark/benchmark_registry.py +++ b/benchmark/benchmark_registry.py @@ -18,45 +18,49 @@ def register_benchmark(name: Optional[str] = None, aliases: Optional[List[str]] = None): """Decorator to automatically register benchmark classes. - + This decorator allows benchmark classes to register themselves automatically, eliminating the need for manual registry maintenance. - + Args: name: Custom name for the benchmark (defaults to class.benchmark_name) aliases: Optional list of alternative names for the benchmark - + Example: >>> @register_benchmark("my_benchmark", aliases=["my_bench", "mb"]) >>> class MyBenchmark(Benchmark): ... benchmark_name = "my_benchmark" ... # ... rest of implementation """ + def decorator(benchmark_class: type) -> type: # Get benchmark name from parameter, class attribute, or class name if name is not None: benchmark_name = name - elif hasattr(benchmark_class, 'benchmark_name') and benchmark_class.benchmark_name: + elif ( + hasattr(benchmark_class, "benchmark_name") + and benchmark_class.benchmark_name + ): benchmark_name = benchmark_class.benchmark_name else: benchmark_name = benchmark_class.__name__.lower() - + # Register main name _BENCHMARK_REGISTRY[benchmark_name.lower()] = benchmark_class - + # Register aliases if aliases: for alias in aliases: _BENCHMARK_REGISTRY[alias.lower()] = benchmark_class - + return benchmark_class - + return decorator def get_registered_benchmarks() -> Dict[str, type]: """Get all registered benchmark classes. - + Returns: Dictionary mapping benchmark names to their classes """ @@ -65,7 +69,7 @@ def get_registered_benchmarks() -> Dict[str, type]: def get_available_benchmark_names() -> List[str]: """Get list of all available benchmark names. - + Returns: Sorted list of registered benchmark names """ @@ -73,61 +77,65 @@ def get_available_benchmark_names() -> List[str]: def create_benchmark_instance( - benchmark_name: str, - subsets: Optional[List[str]] = None + benchmark_name: str, subsets: Optional[List[str]] = None ) -> Benchmark: """Factory function to create benchmark instances by name. - + Uses the automatic registry to instantiate benchmark classes. No manual maintenance required - benchmarks register themselves. - + Args: benchmark_name: Name of the benchmark to create subsets: Optional list of subsets to run for the benchmark - + Returns: Instantiated benchmark object - + Raises: ValueError: If benchmark_name is not registered - + Example: >>> benchmark = create_benchmark_instance("longbench", ["narrativeqa"]) >>> benchmark = create_benchmark_instance("mock_benchmark") """ # Normalize benchmark name benchmark_name = benchmark_name.strip().lower() - + if benchmark_name not in _BENCHMARK_REGISTRY: available_benchmarks: List[str] = get_available_benchmark_names() raise ValueError( f"Unknown benchmark '{benchmark_name}'. Available benchmarks: {available_benchmarks}" ) - + benchmark_class = _BENCHMARK_REGISTRY[benchmark_name] - + try: # Create instance with optional subsets benchmark_instance: Benchmark = benchmark_class(subsets_to_run=subsets) return benchmark_instance - + except Exception as e: raise RuntimeError(f"Failed to instantiate benchmark '{benchmark_name}': {e}") def ensure_benchmarks_loaded() -> None: """Ensure all benchmark modules are loaded to trigger registration. - + This function imports all benchmark modules to ensure their decorators have been executed and they're registered in the global registry. """ import benchmark - + # Get all modules in the benchmark package benchmark_package_path = benchmark.__path__ - + for importer, module_name, ispkg in pkgutil.iter_modules(benchmark_package_path): - if not ispkg and module_name != '__init__' and module_name != 'base' and module_name != 'benchmark_registry': + if ( + not ispkg + and module_name != "__init__" + and module_name != "base" + and module_name != "benchmark_registry" + ): try: # Import the module to trigger @register_benchmark decorators module_full_name = f"benchmark.{module_name}" @@ -139,27 +147,29 @@ def ensure_benchmarks_loaded() -> None: continue -def validate_benchmark_config(benchmark_name: str, subsets: Optional[List[str]] = None) -> None: +def validate_benchmark_config( + benchmark_name: str, subsets: Optional[List[str]] = None +) -> None: """Validate a benchmark configuration against available benchmarks. - + This function checks if the benchmark exists and if specified subsets are valid. - + Args: benchmark_name: Name of the benchmark to validate subsets: Optional list of subsets to validate - + Raises: ValueError: If benchmark or subsets are invalid - + Example: >>> validate_benchmark_config("longbench", ["narrativeqa"]) # Passes validation - >>> + >>> >>> validate_benchmark_config("invalid_benchmark") # Raises ValueError """ try: # Create temporary benchmark instance to validate benchmark = create_benchmark_instance(benchmark_name, subsets=None) - + # Validate subsets if specified if subsets is not None: available_datasets: List[str] = benchmark.get_available_datasets() @@ -169,23 +179,23 @@ def validate_benchmark_config(benchmark_name: str, subsets: Optional[List[str]] f"Invalid subsets for {benchmark_name}: {invalid_subsets}. " f"Available datasets: {available_datasets}" ) - + except Exception as e: raise ValueError(f"Invalid benchmark configuration: {e}") def get_benchmark_subsets(benchmark_name: str) -> Optional[List[str]]: """Get available subsets for a benchmark using the standard interface. - + This is a utility function that can help users determine what subsets are available for a given benchmark using the standard get_available_datasets() method. - + Args: benchmark_name: Name of the benchmark to inspect - + Returns: List of available subset names, or None if benchmark doesn't support subsets - + Example: >>> subsets = get_benchmark_subsets("longbench") >>> print(subsets) # ['narrativeqa', 'qasper', 'multifieldqa_en', ...] @@ -193,8 +203,8 @@ def get_benchmark_subsets(benchmark_name: str) -> Optional[List[str]]: try: benchmark_instance = create_benchmark_instance(benchmark_name) return benchmark_instance.get_available_datasets() - + except Exception as e: # If we can't instantiate the benchmark or get subset info, return None logging.warning(f"Could not get subsets for benchmark '{benchmark_name}': {e}") - return None \ No newline at end of file + return None diff --git a/benchmark/executor.py b/benchmark/executor.py index 49ce54c5..445093a7 100644 --- a/benchmark/executor.py +++ b/benchmark/executor.py @@ -19,8 +19,8 @@ from sparse_attention_hub.metric_logging.logger import MicroMetricLogger # Set multiprocessing start method to 'spawn' for CUDA compatibility -if multiprocessing.get_start_method(allow_none=True) != 'spawn': - multiprocessing.set_start_method('spawn', force=True) +if multiprocessing.get_start_method(allow_none=True) != "spawn": + multiprocessing.set_start_method("spawn", force=True) from sparse_attention_hub.sparse_attention.base import SparseAttentionConfig @@ -34,12 +34,8 @@ BenchmarkFailure, filter_existing_results, generate_benchmark_stubs, - -) -from .benchmark_registry import ( - ensure_benchmarks_loaded, - create_benchmark_instance ) +from .benchmark_registry import ensure_benchmarks_loaded, create_benchmark_instance from .utils.gpu import ( cleanup_gpu_memory, @@ -56,14 +52,15 @@ @contextmanager def set_gpu(gpu_id: int): """Context manager to set the current CUDA device. - + Args: gpu_id: The GPU device ID to set as current device - + Yields: None: The context manager yields control to the with block """ import torch + torch.cuda.set_device(gpu_id) yield @@ -72,22 +69,24 @@ def _signal_handler(signum: int, frame: Any) -> None: """Handle shutdown signals gracefully.""" global _shutdown_requested _shutdown_requested = True - logging.getLogger(__name__).warning(f"Received signal {signum}, initiating graceful shutdown...") + logging.getLogger(__name__).warning( + f"Received signal {signum}, initiating graceful shutdown..." + ) def _categorize_error(error: Exception, context: str = "") -> str: """Categorize errors for better handling and reporting. - + Args: error: The exception that occurred context: Additional context about where the error occurred - + Returns: Error category string for classification """ error_type = type(error).__name__ error_msg = str(error).lower() - + # GPU-related errors if any(keyword in error_msg for keyword in ["cuda", "gpu", "out of memory", "oom"]): if "out of memory" in error_msg or "oom" in error_msg: @@ -96,32 +95,41 @@ def _categorize_error(error: Exception, context: str = "") -> str: return "GPU_CUDA_ERROR" else: return "GPU_ERROR" - + # Model loading errors - elif any(keyword in error_msg for keyword in ["model", "huggingface", "transformers", "pretrained"]): + elif any( + keyword in error_msg + for keyword in ["model", "huggingface", "transformers", "pretrained"] + ): if "not found" in error_msg or "doesn't exist" in error_msg: return "MODEL_NOT_FOUND" elif "tokenizer" in error_msg: return "TOKENIZER_ERROR" else: return "MODEL_LOADING_ERROR" - + # Dataset/benchmark errors elif any(keyword in error_msg for keyword in ["dataset", "benchmark", "subset"]): return "DATASET_ERROR" - + # Network/connection errors - elif any(keyword in error_msg for keyword in ["connection", "timeout", "network", "http"]): + elif any( + keyword in error_msg for keyword in ["connection", "timeout", "network", "http"] + ): return "NETWORK_ERROR" - + # File system errors - elif any(keyword in error_msg for keyword in ["file", "directory", "permission", "disk"]): + elif any( + keyword in error_msg for keyword in ["file", "directory", "permission", "disk"] + ): return "FILESYSTEM_ERROR" - + # Multiprocessing errors - elif any(keyword in error_msg for keyword in ["queue", "process", "multiprocessing"]): + elif any( + keyword in error_msg for keyword in ["queue", "process", "multiprocessing"] + ): return "MULTIPROCESSING_ERROR" - + # Default categories elif isinstance(error, TimeoutError): return "TIMEOUT_ERROR" @@ -140,17 +148,17 @@ def _benchmark_worker( error_queue: multiprocessing.Queue, timeout_per_benchmark: float = 3600.0, micro_metric_logger_max_records: Optional[int] = None, - micro_metric_logger_sampling_factor: float = 1.0 + micro_metric_logger_sampling_factor: float = 1.0, ) -> None: """Worker function to execute benchmarks with dynamic GPU allocation. - + This function runs in a separate process and handles: 1. Acquiring GPUs from the shared pool 2. Creating model adapters with sparse attention configurations 3. Executing benchmarks with proper error handling 4. Releasing GPUs back to the pool 5. Reporting results and errors - + Args: stub_queue: Queue containing BenchmarkStub instances to process gpu_pool: Shared queue containing available GPU IDs @@ -162,11 +170,11 @@ def _benchmark_worker( """ worker_id = os.getpid() logger = logging.getLogger(f"{__name__}.worker_{worker_id}") - + # Set up signal handlers for graceful shutdown signal.signal(signal.SIGTERM, _signal_handler) signal.signal(signal.SIGINT, _signal_handler) - + # Track resources for cleanup current_gpu_id: Optional[int] = None adapter = None @@ -177,7 +185,7 @@ def _benchmark_worker( if _shutdown_requested: logger.info(f"Worker {worker_id}: Shutdown requested, exiting") break - + # Step 1: Get next benchmark stub from queue try: stub: BenchmarkStub = stub_queue.get(timeout=1.0) # 1 second timeout @@ -185,127 +193,154 @@ def _benchmark_worker( # No more work to do logger.info(f"Worker {worker_id}: No more work, shutting down") break - + # Check for sentinel value (shutdown signal) if stub is None: logger.info(f"Worker {worker_id}: Received shutdown signal, exiting") break - + # Step 2: Acquire GPU from pool try: current_gpu_id = acquire_gpu_from_pool(gpu_pool, timeout=30.0) - logger.info(f"Worker {worker_id}: Acquired GPU {current_gpu_id} for {stub.model_name}/{stub.sparse_config_name}/{stub.benchmark_name}") + logger.info( + f"Worker {worker_id}: Acquired GPU {current_gpu_id} for {stub.model_name}/{stub.sparse_config_name}/{stub.benchmark_name}" + ) except Exception as e: error_category = _categorize_error(e, "GPU acquisition") error_msg = f"Failed to acquire GPU for {stub.model_name}/{stub.sparse_config_name}/{stub.benchmark_name}: {e}" logger.error(f"Worker {worker_id}: {error_msg}") - error_queue.put(BenchmarkFailure( - stub=stub, - error_message=error_msg, - error_type=error_category, - execution_time=0.0 - )) + error_queue.put( + BenchmarkFailure( + stub=stub, + error_message=error_msg, + error_type=error_category, + execution_time=0.0, + ) + ) continue # Step 3: Run the benchmark on the current GPU start_time = time.time() execution_time = 0.0 # Initialize execution_time - + try: with set_gpu(current_gpu_id): - logger.debug(f"Worker {worker_id}: Set CUDA device to {current_gpu_id}") + logger.debug( + f"Worker {worker_id}: Set CUDA device to {current_gpu_id}" + ) execution_success = False # Create model adapter with sparse attention config - logger.info(f"Worker {worker_id}: Creating model adapter for {stub.model_name}") - + logger.info( + f"Worker {worker_id}: Creating model adapter for {stub.model_name}" + ) + # Import here to avoid issues with multiprocessing from sparse_attention_hub.adapters.huggingface import ModelAdapterHF - + adapter = ModelAdapterHF( model_name=stub.model_name, sparse_attention_config=stub.sparse_attention_config, model_kwargs=stub.adapter_config.model_kwargs, - tokenizer_kwargs=stub.adapter_config.tokenizer_kwargs + tokenizer_kwargs=stub.adapter_config.tokenizer_kwargs, ) - + # Create benchmark instance - logger.info(f"Worker {worker_id}: Creating benchmark instance for {stub.benchmark_name}") + logger.info( + f"Worker {worker_id}: Creating benchmark instance for {stub.benchmark_name}" + ) benchmark = create_benchmark_instance( benchmark_name=stub.benchmark_name, - subsets=[stub.subset] if stub.subset else None + subsets=[stub.subset] if stub.subset else None, ) - + # Execute benchmark - logger.info(f"Worker {worker_id}: Executing benchmark {stub.benchmark_name} on GPU {current_gpu_id}") + logger.info( + f"Worker {worker_id}: Executing benchmark {stub.benchmark_name} on GPU {current_gpu_id}" + ) metric_logger = MicroMetricLogger() metric_logger.configure_logging( - log_path=stub.result_dir, - enabled_metrics=["research_attention_density", "research_attention_output_error"], + log_path=stub.result_dir, + enabled_metrics=[ + "research_attention_density", + "research_attention_output_error", + ], max_records=micro_metric_logger_max_records, - sampling_factor=micro_metric_logger_sampling_factor + sampling_factor=micro_metric_logger_sampling_factor, ) metrics = benchmark.run_benchmark( adapter=adapter, result_dir=stub.result_dir, generation_kwargs=stub.generation_kwargs, - request_kwargs=stub.request_kwargs + request_kwargs=stub.request_kwargs, ) metric_logger.flush() - + execution_time = time.time() - start_time execution_success = True - + # Report successful result result = BenchmarkResult( stub=stub, metrics=metrics, execution_time=execution_time, - success=True + success=True, ) result_queue.put(result) - - logger.info(f"Worker {worker_id}: Successfully completed {stub.model_name}/{stub.sparse_config_name}/{stub.benchmark_name} in {execution_time:.2f}s") + + logger.info( + f"Worker {worker_id}: Successfully completed {stub.model_name}/{stub.sparse_config_name}/{stub.benchmark_name} in {execution_time:.2f}s" + ) except Exception as e: - execution_time = time.time() - start_time # Calculate execution time even on failure + execution_time = ( + time.time() - start_time + ) # Calculate execution time even on failure error_category = _categorize_error(e, "benchmark execution") error_msg = f"Benchmark execution failed: {e}" logger.error(f"Worker {worker_id}: {error_msg}") - + # Log detailed error information for debugging - logger.debug(f"Worker {worker_id}: Error details: {traceback.format_exc()}") - + logger.debug( + f"Worker {worker_id}: Error details: {traceback.format_exc()}" + ) + # Report failure failure = BenchmarkFailure( stub=stub, error_message=error_msg, error_type=error_category, - execution_time=execution_time + execution_time=execution_time, ) error_queue.put(failure) continue - + finally: # Step 4: Cleanup and release GPU - _cleanup_worker_resources(gpu_pool, current_gpu_id, adapter, logger, worker_id) + _cleanup_worker_resources( + gpu_pool, current_gpu_id, adapter, logger, worker_id + ) current_gpu_id = None adapter = None - + except Exception as worker_error: logger.error(f"Worker {worker_id}: Critical worker error: {worker_error}") - logger.debug(f"Worker {worker_id}: Critical error details: {traceback.format_exc()}") - + logger.debug( + f"Worker {worker_id}: Critical error details: {traceback.format_exc()}" + ) + # Cleanup any remaining resources _cleanup_worker_resources(gpu_pool, current_gpu_id, adapter, logger, worker_id) - + # Report worker failure to error queue - error_queue.put({ - "worker_id": worker_id, - "error_type": "WORKER_CRITICAL_ERROR", - "error_message": str(worker_error), - "error_traceback": traceback.format_exc() - }) + error_queue.put( + { + "worker_id": worker_id, + "error_type": "WORKER_CRITICAL_ERROR", + "error_message": str(worker_error), + "error_traceback": traceback.format_exc(), + } + ) def _cleanup_worker_resources( @@ -313,10 +348,10 @@ def _cleanup_worker_resources( gpu_id: Optional[int], adapter: Any, logger: logging.Logger, - worker_id: int + worker_id: int, ) -> None: """Clean up worker resources including GPU memory and adapter. - + Args: gpu_pool: GPU pool queue to return GPU to gpu_id: GPU ID to release (can be None) - this is the actual GPU ID from the pool @@ -331,53 +366,60 @@ def _cleanup_worker_resources( # Force garbage collection of adapter del adapter import gc + gc.collect() logger.debug(f"Worker {worker_id}: Cleaned up model adapter") except Exception as e: logger.warning(f"Worker {worker_id}: Failed to cleanup adapter: {e}") - + # Clean up GPU memory and release GPU if gpu_id is not None: try: cleanup_gpu_memory(gpu_id) - logger.debug(f"Worker {worker_id}: Cleaned up GPU memory for GPU {gpu_id}") - + logger.debug( + f"Worker {worker_id}: Cleaned up GPU memory for GPU {gpu_id}" + ) + # Release GPU back to pool (always use the original GPU ID for the pool) release_gpu_to_pool(gpu_pool, gpu_id) logger.debug(f"Worker {worker_id}: Released GPU {gpu_id} back to pool") - + except Exception as cleanup_error: - logger.warning(f"Worker {worker_id}: GPU cleanup failed for GPU {gpu_id}: {cleanup_error}") + logger.warning( + f"Worker {worker_id}: GPU cleanup failed for GPU {gpu_id}: {cleanup_error}" + ) # Try to release GPU even if cleanup failed try: release_gpu_to_pool(gpu_pool, gpu_id) except Exception: - logger.error(f"Worker {worker_id}: Failed to release GPU {gpu_id} to pool") - + logger.error( + f"Worker {worker_id}: Failed to release GPU {gpu_id} to pool" + ) + except Exception as e: logger.error(f"Worker {worker_id}: Error during resource cleanup: {e}") class BenchmarkExecutor: """Parallel benchmark executor with dynamic GPU allocation and resumability. - - Executes benchmark experiments across a model ร— sparse_attention_config ร— + + Executes benchmark experiments across a model ร— sparse_attention_config ร— benchmark ร— subset matrix with parallel GPU execution and automatic resumability. - + Features: - Dynamic GPU allocation from specified gpu_ids - Subset-level resumability (skip completed experiments) - Parallel execution with configurable concurrency - Comprehensive error handling and logging - Result aggregation and summary generation - + Example: >>> executor = BenchmarkExecutor( ... gpu_ids=[0, 1, 2, 3], ... max_concurrent_runs=4, ... base_result_dir="./benchmark_results" ... ) - >>> + >>> >>> results = executor.run_benchmark_matrix( ... model_names=["model1", "model2"], ... sparse_attention_configs=[("dense", None), ("sparse", config)], @@ -385,7 +427,7 @@ class BenchmarkExecutor: ... adapter_config=AdapterConfig() ... ) """ - + def __init__( self, gpu_ids: List[int], @@ -396,11 +438,13 @@ def __init__( required_result_files: Optional[List[str]] = None, timeout_per_benchmark: float = 360000.0, # 100 hours default verbose: bool = True, - micro_metric_logger_max_records: Optional[int] = None, # Maximum number of metric events to log + micro_metric_logger_max_records: Optional[ + int + ] = None, # Maximum number of metric events to log micro_metric_logger_sampling_factor: float = 1.0, # Probability of logging each metric event (0.0-1.0) ): """Initialize the BenchmarkExecutor. - + Args: gpu_ids: List of GPU device IDs to use for parallel execution max_concurrent_runs: Maximum number of concurrent benchmark runs @@ -412,61 +456,70 @@ def __init__( verbose: Whether to enable verbose logging micro_metric_logger_max_records: Maximum number of metric events to log (None for unlimited) micro_metric_logger_sampling_factor: Probability of logging each metric event (0.0-1.0) - + Raises: ValueError: If configuration parameters are invalid RuntimeError: If GPU validation fails """ # Validate and store configuration self.gpu_ids = self._validate_gpu_ids(gpu_ids) - self.max_concurrent_runs = self._validate_max_concurrent_runs(max_concurrent_runs) + self.max_concurrent_runs = self._validate_max_concurrent_runs( + max_concurrent_runs + ) self.base_result_dir = Path(base_result_dir).resolve() self.enable_resumability = enable_resumability self.result_file_validation = result_file_validation self.required_result_files = required_result_files or ["raw_results.csv"] self.timeout_per_benchmark = timeout_per_benchmark self.verbose = verbose - + # Metric logging configuration self.micro_metric_logger_max_records = micro_metric_logger_max_records - self.micro_metric_logger_sampling_factor = max(0.0, min(1.0, micro_metric_logger_sampling_factor)) # Clamp to [0.0, 1.0] - + self.micro_metric_logger_sampling_factor = max( + 0.0, min(1.0, micro_metric_logger_sampling_factor) + ) # Clamp to [0.0, 1.0] + # Initialize logging self._setup_logging() - + # Set up signal handlers for graceful shutdown self._setup_signal_handlers() - + # Validate GPU availability self._validate_gpu_setup() - + # Load all available benchmarks ensure_benchmarks_loaded() - - self.logger.info(f"BenchmarkExecutor initialized:") self.logger.info(f" GPU IDs: {self.gpu_ids}") self.logger.info(f" Max concurrent runs: {self.max_concurrent_runs}") self.logger.info(f" Base result directory: {self.base_result_dir}") - self.logger.info(f" Resumability: {'enabled' if self.enable_resumability else 'disabled'}") - self.logger.info(f" Metric logging - Max records: {self.micro_metric_logger_max_records if self.micro_metric_logger_max_records else 'unlimited'}") - self.logger.info(f" Metric logging - Sampling factor: {self.micro_metric_logger_sampling_factor}") - + self.logger.info( + f" Resumability: {'enabled' if self.enable_resumability else 'disabled'}" + ) + self.logger.info( + f" Metric logging - Max records: {self.micro_metric_logger_max_records if self.micro_metric_logger_max_records else 'unlimited'}" + ) + self.logger.info( + f" Metric logging - Sampling factor: {self.micro_metric_logger_sampling_factor}" + ) + def _setup_signal_handlers(self) -> None: """Set up signal handlers for graceful shutdown.""" signal.signal(signal.SIGTERM, _signal_handler) signal.signal(signal.SIGINT, _signal_handler) - + # Register cleanup function to run at exit import atexit + atexit.register(self._cleanup_on_exit) - + def _cleanup_on_exit(self) -> None: """Cleanup function called when the process exits.""" - if hasattr(self, 'logger'): + if hasattr(self, "logger"): self.logger.info("BenchmarkExecutor cleanup on exit") - + # Reset global shutdown flag global _shutdown_requested _shutdown_requested = False @@ -478,13 +531,13 @@ def run_benchmark_matrix( benchmark_configs: List[BenchmarkConfig], adapter_config: AdapterConfig, generation_kwargs: Optional[Dict[str, Any]] = None, - request_kwargs: Optional[Dict[str, Any]] = None + request_kwargs: Optional[Dict[str, Any]] = None, ) -> ExecutionResults: """Execute benchmark matrix with parallel GPU execution. - - Runs all combinations of model_names ร— sparse_attention_configs ร— + + Runs all combinations of model_names ร— sparse_attention_configs ร— benchmark_configs ร— subsets in parallel across available GPUs. - + Args: model_names: List of model names to benchmark sparse_attention_configs: List of (name, config) tuples for sparse attention @@ -492,10 +545,10 @@ def run_benchmark_matrix( adapter_config: Configuration for model adapter generation_kwargs: Optional generation parameters request_kwargs: Optional request processing parameters - + Returns: ExecutionResults containing comprehensive execution information - + Example: >>> results = executor.run_benchmark_matrix( ... model_names=["meta-llama/Llama-3.1-8B-Instruct"], @@ -507,13 +560,13 @@ def run_benchmark_matrix( """ # Initialize execution self.logger.info("Starting benchmark matrix execution") - + try: # Step 1: Validate input parameters self._validate_matrix_parameters( model_names, sparse_attention_configs, benchmark_configs, adapter_config ) - + # Step 2: Generate benchmark stubs (matrix expansion) self.logger.info("Generating benchmark matrix...") all_stubs = generate_benchmark_stubs( @@ -523,14 +576,16 @@ def run_benchmark_matrix( adapter_config=adapter_config, generation_kwargs=generation_kwargs, request_kwargs=request_kwargs, - base_result_dir=str(self.base_result_dir) + base_result_dir=str(self.base_result_dir), ) - + total_combinations = len(all_stubs) self.logger.info(f"Generated {total_combinations} benchmark combinations:") - self.logger.info(f" {len(model_names)} models ร— {len(sparse_attention_configs)} sparse configs ร— " - f"{sum(len(b.subsets) if b.subsets else 1 for b in benchmark_configs)} benchmark-subsets") - + self.logger.info( + f" {len(model_names)} models ร— {len(sparse_attention_configs)} sparse configs ร— " + f"{sum(len(b.subsets) if b.subsets else 1 for b in benchmark_configs)} benchmark-subsets" + ) + # Step 3: Filter for resumability (if enabled) if self.enable_resumability: self.logger.info("Checking for existing results (resumability)...") @@ -538,50 +593,56 @@ def run_benchmark_matrix( all_stubs, check_result_files=self.result_file_validation, required_files=self.required_result_files, - verbose=self.verbose + verbose=self.verbose, + ) + + self.logger.info( + f"Resumability check: {len(completed_stubs)} completed, {len(pending_stubs)} pending" ) - - self.logger.info(f"Resumability check: {len(completed_stubs)} completed, {len(pending_stubs)} pending") else: pending_stubs = all_stubs completed_stubs = [] - self.logger.info("Resumability disabled - will execute all combinations") - + self.logger.info( + "Resumability disabled - will execute all combinations" + ) + # Step 4: Early exit if nothing to do if not pending_stubs: - self.logger.info("No pending benchmarks to execute. All experiments already completed!") - + self.logger.info( + "No pending benchmarks to execute. All experiments already completed!" + ) + execution_summary = { "total_combinations": total_combinations, "models": model_names, "sparse_configs": [name for name, _ in sparse_attention_configs], - "benchmarks": [cfg.benchmark_name for cfg in benchmark_configs] + "benchmarks": [cfg.benchmark_name for cfg in benchmark_configs], } - + progress = ExecutionProgress( total_stubs=total_combinations, skipped_stubs=len(completed_stubs), completed_stubs=0, - failed_stubs=0 + failed_stubs=0, ) - + return ExecutionResults( execution_summary=execution_summary, individual_results=[], failed_executions=[], execution_time=0.0, - progress=progress + progress=progress, ) - - # Step 6: Execute pending benchmarks with worker processes - self.logger.info(f"Executing {len(pending_stubs)} pending benchmarks with {self.max_concurrent_runs} workers...") - + self.logger.info( + f"Executing {len(pending_stubs)} pending benchmarks with {self.max_concurrent_runs} workers..." + ) + start_time = time.time() results = self._execute_with_workers(pending_stubs) execution_time = time.time() - start_time - + # Step 7: Aggregate results execution_summary = { "total_combinations": total_combinations, @@ -590,101 +651,112 @@ def run_benchmark_matrix( "benchmarks": [cfg.benchmark_name for cfg in benchmark_configs], "execution_time_seconds": execution_time, "gpu_ids_used": self.gpu_ids, - "max_concurrent_runs": self.max_concurrent_runs + "max_concurrent_runs": self.max_concurrent_runs, } - + progress = ExecutionProgress( total_stubs=total_combinations, skipped_stubs=len(completed_stubs), completed_stubs=len(results.individual_results), - failed_stubs=len(results.failed_executions) + failed_stubs=len(results.failed_executions), ) - + final_results = ExecutionResults( execution_summary=execution_summary, individual_results=results.individual_results, failed_executions=results.failed_executions, execution_time=execution_time, - progress=progress + progress=progress, ) - + self.logger.info(f"Benchmark matrix execution completed:") self.logger.info(f" Total time: {execution_time:.2f}s") self.logger.info(f" Successful: {len(results.individual_results)}") self.logger.info(f" Failed: {len(results.failed_executions)}") self.logger.info(f" Skipped: {len(completed_stubs)}") - + return final_results - + except Exception as e: self.logger.error(f"Benchmark execution failed: {e}") raise - - def _execute_with_workers(self, pending_stubs: List[BenchmarkStub]) -> ExecutionResults: + + def _execute_with_workers( + self, pending_stubs: List[BenchmarkStub] + ) -> ExecutionResults: """Execute benchmark stubs using worker processes. - + This method implements comprehensive process pool management with: - Dynamic work distribution through shared queues - Graceful process startup and shutdown - Real-time result collection and error handling - Process health monitoring and recovery - + Args: pending_stubs: List of benchmark stubs to execute - + Returns: ExecutionResults containing all results and failures """ - self.logger.info(f"Starting execution with {len(pending_stubs)} stubs using {self.max_concurrent_runs} workers") - + self.logger.info( + f"Starting execution with {len(pending_stubs)} stubs using {self.max_concurrent_runs} workers" + ) + # Step 1: Create and configure shared queues - stub_queue = multiprocessing.Queue(maxsize=len(pending_stubs) + 100) # Buffer for queue operations + stub_queue = multiprocessing.Queue( + maxsize=len(pending_stubs) + 100 + ) # Buffer for queue operations gpu_pool = create_gpu_pool(self.gpu_ids) result_queue = multiprocessing.Queue() error_queue = multiprocessing.Queue() - + # Step 2: Populate work queue with all stubs self.logger.info("Populating work queue...") for stub in pending_stubs: stub_queue.put(stub) - + # Add sentinel values to signal workers to stop for _ in range(self.max_concurrent_runs): stub_queue.put(None) # Sentinel value - + # Step 3: Create and start worker processes workers = [] worker_pids = [] - + self.logger.info(f"Starting {self.max_concurrent_runs} worker processes...") for i in range(self.max_concurrent_runs): worker = multiprocessing.Process( target=_benchmark_worker, - args=(stub_queue, - gpu_pool, - result_queue, - error_queue, - self.timeout_per_benchmark, - self.micro_metric_logger_max_records, - self.micro_metric_logger_sampling_factor - ), - name=f"benchmark_worker_{i}" + args=( + stub_queue, + gpu_pool, + result_queue, + error_queue, + self.timeout_per_benchmark, + self.micro_metric_logger_max_records, + self.micro_metric_logger_sampling_factor, + ), + name=f"benchmark_worker_{i}", + ) + worker.daemon = ( + True # Ensure workers are terminated when main process exits ) - worker.daemon = True # Ensure workers are terminated when main process exits worker.start() workers.append(worker) worker_pids.append(worker.pid) - self.logger.debug(f"Started worker {i+1}/{self.max_concurrent_runs} (PID: {worker.pid})") - + self.logger.debug( + f"Started worker {i+1}/{self.max_concurrent_runs} (PID: {worker.pid})" + ) + self.logger.info(f"All {self.max_concurrent_runs} workers started successfully") - + # Step 4: Monitor and collect results in real-time individual_results: List[BenchmarkResult] = [] failed_executions: List[BenchmarkFailure] = [] active_workers = set(worker_pids) - + self.logger.info("Monitoring worker processes and collecting results...") - + try: # Monitor workers and collect results until all work is complete while active_workers: @@ -699,47 +771,74 @@ def _execute_with_workers(self, pending_stubs: List[BenchmarkStub]) -> Execution if worker.pid in active_workers: active_workers.remove(worker.pid) completed_workers.append(worker) - + if worker.exitcode != 0: - self.logger.warning(f"Worker {worker.pid} exited with code {worker.exitcode}") + self.logger.warning( + f"Worker {worker.pid} exited with code {worker.exitcode}" + ) else: - self.logger.debug(f"Worker {worker.pid} completed successfully") - + self.logger.debug( + f"Worker {worker.pid} completed successfully" + ) + # Collect any available results (non-blocking) - self._collect_available_results(result_queue, error_queue, individual_results, failed_executions) - + self._collect_available_results( + result_queue, error_queue, individual_results, failed_executions + ) + # Log progress periodically - if len(individual_results) + len(failed_executions) > 0 and (len(individual_results) + len(failed_executions)) % 5 == 0: - self.logger.info(f"Progress: {len(individual_results)} completed, {len(failed_executions)} failed, {len(active_workers)} workers active") - + if ( + len(individual_results) + len(failed_executions) > 0 + and (len(individual_results) + len(failed_executions)) % 5 == 0 + ): + self.logger.info( + f"Progress: {len(individual_results)} completed, {len(failed_executions)} failed, {len(active_workers)} workers active" + ) + # Small delay to prevent busy waiting time.sleep(0.1) - + # Step 5: Final result collection self.logger.info("All workers completed, collecting final results...") - self._collect_available_results(result_queue, error_queue, individual_results, failed_executions) - + self._collect_available_results( + result_queue, error_queue, individual_results, failed_executions + ) + except KeyboardInterrupt: - self.logger.warning("Received interrupt signal, initiating graceful shutdown...") - self._graceful_shutdown(workers, stub_queue, gpu_pool, result_queue, error_queue) + self.logger.warning( + "Received interrupt signal, initiating graceful shutdown..." + ) + self._graceful_shutdown( + workers, stub_queue, gpu_pool, result_queue, error_queue + ) raise - + except Exception as e: error_category = _categorize_error(e, "main execution") self.logger.error(f"Error during execution ({error_category}): {e}") self.logger.debug(f"Execution error details: {traceback.format_exc()}") - self._graceful_shutdown(workers, stub_queue, gpu_pool, result_queue, error_queue) + self._graceful_shutdown( + workers, stub_queue, gpu_pool, result_queue, error_queue + ) raise - + finally: # Step 6: Cleanup resources - self._cleanup_resources(workers, stub_queue, gpu_pool, result_queue, error_queue) - + self._cleanup_resources( + workers, stub_queue, gpu_pool, result_queue, error_queue + ) + # Step 7: Final summary total_processed = len(individual_results) + len(failed_executions) - self.logger.info(f"Execution completed: {len(individual_results)} successful, {len(failed_executions)} failed") - self.logger.info(f"Success rate: {len(individual_results)/total_processed*100:.1f}%" if total_processed > 0 else "No work processed") - + self.logger.info( + f"Execution completed: {len(individual_results)} successful, {len(failed_executions)} failed" + ) + self.logger.info( + f"Success rate: {len(individual_results)/total_processed*100:.1f}%" + if total_processed > 0 + else "No work processed" + ) + return ExecutionResults( execution_summary={}, # Will be filled by caller individual_results=individual_results, @@ -748,19 +847,19 @@ def _execute_with_workers(self, pending_stubs: List[BenchmarkStub]) -> Execution progress=ExecutionProgress( total_stubs=len(pending_stubs), completed_stubs=len(individual_results), - failed_stubs=len(failed_executions) - ) + failed_stubs=len(failed_executions), + ), ) - + def _collect_available_results( self, result_queue: multiprocessing.Queue, error_queue: multiprocessing.Queue, individual_results: List[BenchmarkResult], - failed_executions: List[BenchmarkFailure] + failed_executions: List[BenchmarkFailure], ) -> None: """Collect all available results from queues without blocking. - + Args: result_queue: Queue containing successful benchmark results error_queue: Queue containing benchmark failures @@ -774,7 +873,7 @@ def _collect_available_results( individual_results.append(result) except Empty: break - + # Collect all available errors while True: try: @@ -786,17 +885,17 @@ def _collect_available_results( self.logger.error(f"Worker error: {error}") except Empty: break - + def _graceful_shutdown( self, workers: List[multiprocessing.Process], stub_queue: multiprocessing.Queue, gpu_pool: multiprocessing.Queue, result_queue: multiprocessing.Queue, - error_queue: multiprocessing.Queue + error_queue: multiprocessing.Queue, ) -> None: """Perform graceful shutdown of worker processes and queues. - + Args: workers: List of worker processes to terminate stub_queue: Work queue to close @@ -805,7 +904,7 @@ def _graceful_shutdown( error_queue: Error queue to close """ self.logger.info("Initiating graceful shutdown...") - + try: # Signal workers to stop by adding sentinel values sentinel_count = 0 @@ -816,9 +915,9 @@ def _graceful_shutdown( except Exception as e: self.logger.debug(f"Could not add sentinel to queue: {e}") break # Queue is full, stop adding sentinels - + self.logger.info(f"Added {sentinel_count} shutdown signals to work queue") - + # Wait for workers to finish with timeout self.logger.info("Waiting for workers to finish...") for i, worker in enumerate(workers): @@ -829,16 +928,20 @@ def _graceful_shutdown( worker.terminate() worker.join(timeout=5.0) if worker.is_alive(): - self.logger.error(f"Failed to terminate worker {worker.pid}, killing process") + self.logger.error( + f"Failed to terminate worker {worker.pid}, killing process" + ) worker.kill() worker.join(timeout=2.0) else: - self.logger.debug(f"Worker {worker.pid} terminated successfully") + self.logger.debug( + f"Worker {worker.pid} terminated successfully" + ) except Exception as e: self.logger.error(f"Error during worker {worker.pid} shutdown: {e}") - + self.logger.info("Graceful shutdown completed") - + except Exception as e: self.logger.error(f"Error during graceful shutdown: {e}") # Force cleanup of remaining workers @@ -848,17 +951,17 @@ def _graceful_shutdown( worker.kill() except Exception: pass - + def _cleanup_resources( self, workers: List[multiprocessing.Process], stub_queue: multiprocessing.Queue, gpu_pool: multiprocessing.Queue, result_queue: multiprocessing.Queue, - error_queue: multiprocessing.Queue + error_queue: multiprocessing.Queue, ) -> None: """Clean up all multiprocessing resources. - + Args: workers: List of worker processes stub_queue: Work queue to close @@ -867,7 +970,7 @@ def _cleanup_resources( error_queue: Error queue to close """ self.logger.debug("Cleaning up multiprocessing resources...") - + # Close all queues try: stub_queue.close() @@ -876,7 +979,7 @@ def _cleanup_resources( error_queue.close() except Exception as e: self.logger.warning(f"Error closing queues: {e}") - + # Join any remaining workers for worker in workers: if worker.is_alive(): @@ -885,17 +988,17 @@ def _cleanup_resources( worker.join(timeout=5.0) if worker.is_alive(): worker.kill() - + self.logger.debug("Resource cleanup completed") - + def _validate_gpu_ids(self, gpu_ids: List[int]) -> List[int]: """Validate and return GPU IDs.""" if not gpu_ids: raise ValueError("gpu_ids cannot be empty") - + if not all(isinstance(gpu_id, int) and gpu_id >= 0 for gpu_id in gpu_ids): raise ValueError("All GPU IDs must be non-negative integers") - + # Remove duplicates while preserving order seen = set() unique_gpu_ids = [] @@ -903,34 +1006,38 @@ def _validate_gpu_ids(self, gpu_ids: List[int]) -> List[int]: if gpu_id not in seen: seen.add(gpu_id) unique_gpu_ids.append(gpu_id) - + return unique_gpu_ids - + def _validate_max_concurrent_runs(self, max_concurrent_runs: int) -> int: """Validate and return max_concurrent_runs.""" if not isinstance(max_concurrent_runs, int) or max_concurrent_runs <= 0: raise ValueError("max_concurrent_runs must be a positive integer") - - if max_concurrent_runs > len(self.gpu_ids) if hasattr(self, 'gpu_ids') else True: + + if ( + max_concurrent_runs > len(self.gpu_ids) + if hasattr(self, "gpu_ids") + else True + ): # This is just a warning - user might want more concurrent runs than GPUs # for benchmarks that don't require much GPU memory pass - + return max_concurrent_runs - + def _setup_logging(self) -> None: """Setup logging configuration.""" self.logger = logging.getLogger(f"{__name__}.BenchmarkExecutor") - + if self.verbose and not self.logger.handlers: handler = logging.StreamHandler() formatter = logging.Formatter( - '%(asctime)s - %(name)s - %(levelname)s - %(message)s' + "%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) handler.setFormatter(formatter) self.logger.addHandler(handler) self.logger.setLevel(logging.INFO) - + def _validate_gpu_setup(self) -> None: """Validate GPU availability.""" try: @@ -939,47 +1046,53 @@ def _validate_gpu_setup(self) -> None: except (RuntimeError, ValueError) as e: self.logger.error(f"GPU validation failed: {e}") raise - + def _validate_matrix_parameters( self, model_names: List[str], sparse_attention_configs: List[Tuple[str, Optional[SparseAttentionConfig]]], benchmark_configs: List[BenchmarkConfig], - adapter_config: AdapterConfig + adapter_config: AdapterConfig, ) -> None: """Validate benchmark matrix parameters.""" if not model_names: raise ValueError("model_names cannot be empty") - + if not sparse_attention_configs: raise ValueError("sparse_attention_configs cannot be empty") - + if not benchmark_configs: raise ValueError("benchmark_configs cannot be empty") - + # Validate model names for model_name in model_names: if not isinstance(model_name, str) or not model_name.strip(): raise ValueError(f"Invalid model name: {model_name}") - + # Validate sparse attention configs for sparse_config in sparse_attention_configs: if not isinstance(sparse_config, tuple) or len(sparse_config) != 2: - raise ValueError(f"sparse_attention_configs must be list of (name, config) tuples") - + raise ValueError( + f"sparse_attention_configs must be list of (name, config) tuples" + ) + config_name, config_obj = sparse_config if not isinstance(config_name, str) or not config_name.strip(): - raise ValueError(f"Sparse config name must be non-empty string: {config_name}") - + raise ValueError( + f"Sparse config name must be non-empty string: {config_name}" + ) + # Validate benchmark configs for benchmark_config in benchmark_configs: if not isinstance(benchmark_config, BenchmarkConfig): - raise ValueError(f"benchmark_configs must contain BenchmarkConfig instances") + raise ValueError( + f"benchmark_configs must contain BenchmarkConfig instances" + ) # Additional validation could be added here if needed - + # Validate adapter config if not isinstance(adapter_config, AdapterConfig): raise ValueError("adapter_config must be an AdapterConfig instance") # Additional validation could be added here if needed - + self.logger.info("Matrix parameter validation passed") diff --git a/benchmark/executor_config.py b/benchmark/executor_config.py index 081d1871..9ef7febf 100644 --- a/benchmark/executor_config.py +++ b/benchmark/executor_config.py @@ -25,53 +25,53 @@ acquire_gpu_from_pool, release_gpu_to_pool, validate_gpu_for_model, - cleanup_gpu_memory + cleanup_gpu_memory, ) @dataclass class BenchmarkConfig: """Configuration for a benchmark execution. - + During stub generation, this expands to individual BenchmarkStub per subset. Each BenchmarkStub will have a single subset value for resumability. - + Attributes: benchmark_name: Name of the benchmark (e.g., "longbench", "mock_benchmark") subsets: Optional list of dataset subsets to run (e.g., ["narrativeqa", "qasper"]) If None, runs all available subsets for the benchmark - + Example: >>> config = BenchmarkConfig("longbench", ["narrativeqa", "qasper"]) >>> # This will create 2 BenchmarkStub instances during matrix expansion """ - + benchmark_name: str subsets: Optional[List[str]] = None - + def __post_init__(self) -> None: """Validate benchmark configuration after initialization. - + Raises: ValueError: If benchmark_name is empty or invalid. """ if not self.benchmark_name or not self.benchmark_name.strip(): raise ValueError("benchmark_name cannot be empty") - + self.benchmark_name = self.benchmark_name.strip() - + if self.subsets is not None: # Remove empty strings and strip whitespace self.subsets = [subset.strip() for subset in self.subsets if subset.strip()] if not self.subsets: self.subsets = None - + def validate_with_benchmark_instance(self, benchmark: Benchmark) -> None: """Validate subsets against actual benchmark instance. - + Args: benchmark: Benchmark instance to validate against - + Raises: ValueError: If any subset is not available in the benchmark. """ @@ -88,47 +88,47 @@ def validate_with_benchmark_instance(self, benchmark: Benchmark) -> None: @dataclass class AdapterConfig: """Base configuration for model adapters (sparse attention config is part of matrix). - + Note: sparse_attention_config is now part of the execution matrix, not base config. This allows testing different sparse attention configurations with the same adapter base. - + Attributes: adapter_name: Name of the adapter type (default: "huggingface") model_kwargs: Additional keyword arguments for model creation tokenizer_kwargs: Additional keyword arguments for tokenizer creation - + Example: >>> config = AdapterConfig( ... model_kwargs={"torch_dtype": torch.bfloat16}, ... tokenizer_kwargs={"padding_side": "left"} ... ) """ - + adapter_name: str = "huggingface" model_kwargs: Optional[Dict[str, Any]] = None tokenizer_kwargs: Optional[Dict[str, Any]] = None - + def __post_init__(self) -> None: """Initialize default values and validate configuration.""" if self.model_kwargs is None: self.model_kwargs = {} if self.tokenizer_kwargs is None: self.tokenizer_kwargs = {} - + if not self.adapter_name or not self.adapter_name.strip(): raise ValueError("adapter_name cannot be empty") - + self.adapter_name = self.adapter_name.strip() @dataclass class BenchmarkStub: """A single benchmark execution task (model ร— sparse_config ร— benchmark ร— subset). - + This represents one atomic execution unit that will be processed by a worker process. Each stub corresponds to a specific combination of model, sparse attention config, benchmark, and subset (if applicable). - + Attributes: model_name: HuggingFace model name (e.g., "meta-llama/Llama-3.1-8B-Instruct") sparse_config_name: Human-readable name for sparse config (e.g., "dense", "streaming") @@ -139,7 +139,7 @@ class BenchmarkStub: generation_kwargs: Parameters for model inference/generation request_kwargs: Parameters for request processing (e.g., max_context_length) result_dir: Full path to directory where results should be saved - + Example: >>> stub = BenchmarkStub( ... model_name="microsoft/Phi-4-mini-instruct", @@ -153,7 +153,7 @@ class BenchmarkStub: ... result_dir="/path/to/results/phi4_dense_longbench_narrativeqa" ... ) """ - + model_name: str sparse_config_name: str sparse_attention_config: Optional[SparseAttentionConfig] @@ -163,7 +163,7 @@ class BenchmarkStub: generation_kwargs: Dict[str, Any] request_kwargs: Dict[str, Any] result_dir: str - + def __post_init__(self) -> None: """Validate benchmark stub configuration.""" if not self.model_name or not self.model_name.strip(): @@ -174,13 +174,13 @@ def __post_init__(self) -> None: raise ValueError("benchmark_name cannot be empty") if not self.result_dir or not self.result_dir.strip(): raise ValueError("result_dir cannot be empty") - + # Trim whitespace self.model_name = self.model_name.strip() self.sparse_config_name = self.sparse_config_name.strip() self.benchmark_name = self.benchmark_name.strip() self.result_dir = self.result_dir.strip() - + if self.subset is not None: self.subset = self.subset.strip() if self.subset.strip() else None @@ -188,7 +188,7 @@ def __post_init__(self) -> None: @dataclass class BenchmarkResult: """Result from a single benchmark execution. - + Attributes: stub: The benchmark stub that was executed metrics: Evaluation metrics returned by benchmark.run_benchmark() @@ -196,7 +196,7 @@ class BenchmarkResult: success: Whether the benchmark executed successfully error_message: Error message if execution failed """ - + stub: BenchmarkStub metrics: Optional[Dict[str, Any]] execution_time: float @@ -207,14 +207,14 @@ class BenchmarkResult: @dataclass class BenchmarkFailure: """Information about a failed benchmark execution. - + Attributes: stub: The benchmark stub that failed error_message: Description of the failure error_type: Type of error that occurred execution_time: Time spent before failure in seconds """ - + stub: BenchmarkStub error_message: str error_type: str @@ -224,7 +224,7 @@ class BenchmarkFailure: @dataclass class ExecutionProgress: """Tracks execution progress across all processes. - + Attributes: total_stubs: Total number of benchmark stubs to execute skipped_stubs: Number of stubs skipped due to existing results (resumability) @@ -232,30 +232,39 @@ class ExecutionProgress: failed_stubs: Number of stubs that failed execution current_executions: Mapping of GPU ID to current task description """ - + total_stubs: int skipped_stubs: int = 0 completed_stubs: int = 0 failed_stubs: int = 0 current_executions: Dict[int, str] = field(default_factory=dict) - + @property def pending_stubs(self) -> int: """Calculate number of stubs pending execution.""" - return self.total_stubs - self.skipped_stubs - self.completed_stubs - self.failed_stubs - + return ( + self.total_stubs + - self.skipped_stubs + - self.completed_stubs + - self.failed_stubs + ) + @property def completion_percentage(self) -> float: """Calculate completion percentage (0-100).""" if self.total_stubs == 0: return 100.0 - return (self.completed_stubs + self.failed_stubs) / (self.total_stubs - self.skipped_stubs) * 100.0 + return ( + (self.completed_stubs + self.failed_stubs) + / (self.total_stubs - self.skipped_stubs) + * 100.0 + ) @dataclass class ExecutionResults: """Aggregated results from benchmark execution. - + Attributes: execution_summary: Summary metadata about the execution individual_results: List of successful benchmark results @@ -263,7 +272,7 @@ class ExecutionResults: execution_time: Total execution time in seconds progress: Final progress statistics """ - + execution_summary: Dict[str, Any] individual_results: List[BenchmarkResult] failed_executions: List[BenchmarkFailure] @@ -283,35 +292,35 @@ class ExecutionResults: create_benchmark_instance, ensure_benchmarks_loaded, validate_benchmark_config as _validate_benchmark_config_base, - get_benchmark_subsets + get_benchmark_subsets, ) def validate_benchmark_config(config: BenchmarkConfig) -> None: """Validate a benchmark configuration against available benchmarks. - + This function checks if the benchmark exists and if specified subsets are valid. - + Args: config: BenchmarkConfig to validate - + Raises: ValueError: If benchmark or subsets are invalid - + Example: >>> config = BenchmarkConfig("longbench", ["narrativeqa"]) >>> validate_benchmark_config(config) # Passes validation - >>> + >>> >>> config = BenchmarkConfig("invalid_benchmark") >>> validate_benchmark_config(config) # Raises ValueError """ try: # Create temporary benchmark instance to validate benchmark = create_benchmark_instance(config.benchmark_name, subsets=None) - + # Validate subsets if specified config.validate_with_benchmark_instance(benchmark) - + except Exception as e: raise ValueError(f"Invalid benchmark configuration: {e}") @@ -320,6 +329,7 @@ def validate_benchmark_config(config: BenchmarkConfig) -> None: # Matrix Expansion and Benchmark Stub Generation Functions # ============================================================================= + def generate_benchmark_stubs( model_names: List[str], sparse_attention_configs: List[Tuple[str, Optional[SparseAttentionConfig]]], @@ -327,13 +337,13 @@ def generate_benchmark_stubs( adapter_config: AdapterConfig, generation_kwargs: Optional[Dict[str, Any]] = None, request_kwargs: Optional[Dict[str, Any]] = None, - base_result_dir: str = "./benchmark_results" + base_result_dir: str = "./benchmark_results", ) -> List[BenchmarkStub]: """Generate all benchmark stubs for the model ร— sparse_config ร— benchmark ร— subset matrix. - + Creates BenchmarkStub instances for every combination of: - model_names ร— sparse_attention_configs ร— benchmark_configs ร— subsets - + Args: model_names: List of model names to benchmark sparse_attention_configs: List of (name, config) tuples for sparse attention @@ -342,13 +352,13 @@ def generate_benchmark_stubs( generation_kwargs: Optional generation parameters request_kwargs: Optional request processing parameters base_result_dir: Base directory for storing results - + Returns: List of BenchmarkStub instances representing all combinations - + Example: >>> stubs = generate_benchmark_stubs( - ... model_names=["model1", "model2"], + ... model_names=["model1", "model2"], ... sparse_attention_configs=[("dense", None), ("sparse", config)], ... benchmark_configs=[BenchmarkConfig("longbench", ["narrativeqa"])], ... adapter_config=AdapterConfig() @@ -356,14 +366,14 @@ def generate_benchmark_stubs( >>> len(stubs) # 2 models ร— 2 configs ร— 1 benchmark ร— 1 subset = 4 4 """ - + if generation_kwargs is None: generation_kwargs = {} if request_kwargs is None: request_kwargs = {} - + stubs: List[BenchmarkStub] = [] - + # Expand the full matrix: model ร— sparse_config ร— benchmark ร— subset for model_name in model_names: for sparse_config_name, sparse_attention_config in sparse_attention_configs: @@ -376,9 +386,9 @@ def generate_benchmark_stubs( model_name=model_name, sparse_config_name=sparse_config_name, benchmark_name=benchmark_config.benchmark_name, - subset=subset + subset=subset, ) - + stub = BenchmarkStub( model_name=model_name, sparse_config_name=sparse_config_name, @@ -388,10 +398,10 @@ def generate_benchmark_stubs( adapter_config=adapter_config, generation_kwargs=generation_kwargs.copy(), request_kwargs=request_kwargs.copy(), - result_dir=result_dir + result_dir=result_dir, ) stubs.append(stub) - + else: # Handle benchmarks with no subsets (run full benchmark) result_dir = construct_result_directory( @@ -399,9 +409,9 @@ def generate_benchmark_stubs( model_name=model_name, sparse_config_name=sparse_config_name, benchmark_name=benchmark_config.benchmark_name, - subset=None + subset=None, ) - + stub = BenchmarkStub( model_name=model_name, sparse_config_name=sparse_config_name, @@ -411,10 +421,10 @@ def generate_benchmark_stubs( adapter_config=adapter_config, generation_kwargs=generation_kwargs.copy(), request_kwargs=request_kwargs.copy(), - result_dir=result_dir + result_dir=result_dir, ) stubs.append(stub) - + return stubs @@ -422,50 +432,50 @@ def filter_existing_results( stubs: List[BenchmarkStub], check_result_files: bool = True, required_files: Optional[List[str]] = None, - verbose: bool = True + verbose: bool = True, ) -> Tuple[List[BenchmarkStub], List[BenchmarkStub]]: """Filter benchmark stubs to skip already completed experiments (resumability). - + Checks each stub's result_dir to determine if the experiment has already been completed. This enables resuming interrupted benchmark runs. - + Args: stubs: List of benchmark stubs to filter check_result_files: Whether to check for specific result files (not just directory) required_files: List of filenames that must exist for completion (default: ["results.json"]) verbose: Whether to log skipped combinations - + Returns: Tuple of (pending_stubs, completed_stubs) where: - pending_stubs: Stubs that need to be executed - completed_stubs: Stubs that have already been completed - + Example: >>> pending, completed = filter_existing_results(all_stubs) >>> print(f"Found {len(completed)} completed, {len(pending)} pending") """ if required_files is None: required_files = ["raw_results.csv"] - + pending_stubs: List[BenchmarkStub] = [] completed_stubs: List[BenchmarkStub] = [] - + for stub in stubs: result_path = Path(stub.result_dir) print(f"Checking result directory: {result_path}", flush=True) - + # Check if result directory exists if not result_path.exists(): pending_stubs.append(stub) continue - + # If not checking result files, just check directory existence if not check_result_files: completed_stubs.append(stub) if verbose: logging.info(f"Skipping completed experiment: {stub.result_dir}") continue - + # Check for required result files all_files_exist = True for required_file in required_files: @@ -473,20 +483,24 @@ def filter_existing_results( if not file_path.exists() or not file_path.is_file(): all_files_exist = False break - + if all_files_exist: completed_stubs.append(stub) if verbose: - logging.info(f"Skipping completed experiment (has {required_files}): {stub.result_dir}") + logging.info( + f"Skipping completed experiment (has {required_files}): {stub.result_dir}" + ) else: pending_stubs.append(stub) if verbose: logging.info(f"Pending experiment (missing results): {stub.result_dir}") - + if verbose: total = len(stubs) completed_count = len(completed_stubs) pending_count = len(completed_stubs) - logging.info(f"Resumability check: {completed_count}/{total} completed, {pending_count}/{total} pending") - - return pending_stubs, completed_stubs \ No newline at end of file + logging.info( + f"Resumability check: {completed_count}/{total} completed, {pending_count}/{total} pending" + ) + + return pending_stubs, completed_stubs diff --git a/benchmark/infinite_bench/__init__.py b/benchmark/infinite_bench/__init__.py index 2a5de88d..7f26a1ea 100644 --- a/benchmark/infinite_bench/__init__.py +++ b/benchmark/infinite_bench/__init__.py @@ -8,4 +8,4 @@ from .calculate_metrics import calculate_metrics from .infinite_bench import InfiniteBench -__all__ = ["calculate_metrics", "InfiniteBench"] \ No newline at end of file +__all__ = ["calculate_metrics", "InfiniteBench"] diff --git a/benchmark/infinite_bench/calculate_metrics.py b/benchmark/infinite_bench/calculate_metrics.py index e9937896..489d8fb3 100644 --- a/benchmark/infinite_bench/calculate_metrics.py +++ b/benchmark/infinite_bench/calculate_metrics.py @@ -365,7 +365,9 @@ def get_score_one(pred: str, label: str, task_name: str, model_name: str) -> flo "math_calc": get_score_one_math_calc, } if task_name == "longbook_sum_eng": - raise AssertionError("Longbook sum task is not supported due to a conflict with rouge library. ") + raise AssertionError( + "Longbook sum task is not supported due to a conflict with rouge library. " + ) assert task_name in NAME_TO_SCORE_GETTER, f"Invalid task name: {task_name}" score = NAME_TO_SCORE_GETTER[task_name](pred, label, model_name) return float(score) diff --git a/benchmark/infinite_bench/create_huggingface_dataset.py b/benchmark/infinite_bench/create_huggingface_dataset.py index 60303fa5..363b0413 100644 --- a/benchmark/infinite_bench/create_huggingface_dataset.py +++ b/benchmark/infinite_bench/create_huggingface_dataset.py @@ -156,7 +156,8 @@ def update_math_find_context(row): df["context"] = df.apply(update_math_find_context, axis=1) df["context"] = df["context"].apply( lambda x: x.replace( - "You should answer with only one number, no other words. The largest number of the list is:", "" + "You should answer with only one number, no other words. The largest number of the list is:", + "", ) ) elif task == "code_run": @@ -177,13 +178,19 @@ def update_context(row): df["context"] = df.apply(update_context, axis=1) else: - df["context"] = df["context"].apply(lambda x: context_prefix[task].format(context=x)) + df["context"] = df["context"].apply( + lambda x: context_prefix[task].format(context=x) + ) if task in ["longbook_choice_eng", "code_debug"]: df["question"] = df["question"] + df["options"].apply( - lambda x: question_template[task].format(OPTION_A=x[0], OPTION_B=x[1], OPTION_C=x[2], OPTION_D=x[3]) + lambda x: question_template[task].format( + OPTION_A=x[0], OPTION_B=x[1], OPTION_C=x[2], OPTION_D=x[3] + ) + ) + df["answer"] = df.apply( + lambda row: ["ABCD"[list(row.options).index(row.answer)]], axis=1 ) - df["answer"] = df.apply(lambda row: ["ABCD"[list(row.options).index(row.answer)]], axis=1) if task == "kv_retrieval": # moved to answer prefix diff --git a/benchmark/infinite_bench/infinite_bench.py b/benchmark/infinite_bench/infinite_bench.py index 3b1bd50b..9a373e05 100644 --- a/benchmark/infinite_bench/infinite_bench.py +++ b/benchmark/infinite_bench/infinite_bench.py @@ -31,34 +31,37 @@ class InfiniteBench(Benchmark): # All available InfiniteBench datasets all_datasets: List[str] = [ "passkey", - "kv_retrieval", + "kv_retrieval", "number_string", "code_run", "code_debug", "math_find", "longbook_qa_eng", "longdialogue_qa_eng", - "longbook_choice_eng" + "longbook_choice_eng", ] - + benchmark_name: str = "infinite_bench" huggingface_dataset_id: str = "MaxJeblick/InfiniteBench" def _load_datasets(self) -> pd.DataFrame: """Load InfiniteBench datasets by individual configs. - + InfiniteBench requires loading each subset as a separate config. - + Returns: Combined pandas DataFrame with all samples from subsets_to_run. """ print(f"Loading InfiniteBench datasets: {self.subsets_to_run}") dfs = [] - + for subset in self.subsets_to_run: try: from datasets import load_dataset - subset_dataset = load_dataset(self.huggingface_dataset_id, subset, split="test") + + subset_dataset = load_dataset( + self.huggingface_dataset_id, subset, split="test" + ) subset_df = subset_dataset.to_pandas() subset_df["task"] = subset # Ensure task column exists dfs.append(subset_df) @@ -66,12 +69,13 @@ def _load_datasets(self) -> pd.DataFrame: except Exception as subset_error: print(f" โŒ Failed to load {subset}: {str(subset_error)}") continue - + if not dfs: raise Exception("No InfiniteBench subsets could be loaded successfully") - + # Combine all subset DataFrames import pandas as pd + combined_df = pd.concat(dfs, ignore_index=True) print(f"Combined {len(combined_df)} total samples from {len(dfs)} subsets") return combined_df @@ -97,7 +101,7 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: task_groups = results_df.groupby("task") task_scores: Dict[str, float] = {} all_scores: List[float] = [] - + for task_name, task_df in task_groups: try: # Use the calculate_metrics function from HashAttention evaluation @@ -105,21 +109,23 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: task_scores[task_name] = score all_scores.append(score) print(f" โœ“ {task_name}: {score:.4f}") - + except Exception as e: print(f"Error evaluating task {task_name}: {str(e)}") task_scores[task_name] = 0.0 # Compute overall metrics overall_score = sum(all_scores) / len(all_scores) if all_scores else 0.0 - + overall_metrics: Dict[str, Any] = { "overall_score": round(overall_score, 4), - "task_scores": {task: round(score, 4) for task, score in task_scores.items()}, + "task_scores": { + task: round(score, 4) for task, score in task_scores.items() + }, "summary": { "total_tasks": len(task_scores), - "total_samples": len(results_df) - } + "total_samples": len(results_df), + }, } - - return overall_metrics \ No newline at end of file + + return overall_metrics diff --git a/benchmark/longbench/__init__.py b/benchmark/longbench/__init__.py index f757aa48..fa3bebde 100644 --- a/benchmark/longbench/__init__.py +++ b/benchmark/longbench/__init__.py @@ -8,4 +8,4 @@ from .calculate_metrics import calculate_metrics, calculate_metrics_e from .longbench import LongBench -__all__ = ["calculate_metrics", "calculate_metrics_e", "LongBench"] \ No newline at end of file +__all__ = ["calculate_metrics", "calculate_metrics_e", "LongBench"] diff --git a/benchmark/longbench/calculate_metrics.py b/benchmark/longbench/calculate_metrics.py index 05fb322c..8c491bc5 100644 --- a/benchmark/longbench/calculate_metrics.py +++ b/benchmark/longbench/calculate_metrics.py @@ -43,7 +43,12 @@ def scorer_e(dataset, predictions, answers, lengths, all_classes): if dataset in ["trec", "triviaqa", "samsum", "lsht"]: prediction = prediction.lstrip("\n").split("\n")[0] for ground_truth in ground_truths: - score = max(score, dataset2metric[dataset](prediction, ground_truth, all_classes=all_classes)) + score = max( + score, + dataset2metric[dataset]( + prediction, ground_truth, all_classes=all_classes + ), + ) if length < 4000: scores["0-4k"].append(score) elif length < 8000: @@ -62,7 +67,12 @@ def scorer(dataset, predictions, answers, all_classes): if dataset in ["trec", "triviaqa", "samsum", "lsht"]: prediction = prediction.lstrip("\n").split("\n")[0] for ground_truth in ground_truths: - score = max(score, dataset2metric[dataset](prediction, ground_truth, all_classes=all_classes)) + score = max( + score, + dataset2metric[dataset]( + prediction, ground_truth, all_classes=all_classes + ), + ) total_score += score return round(100 * total_score / len(predictions), 2) diff --git a/benchmark/longbench/create_huggingface_dataset.py b/benchmark/longbench/create_huggingface_dataset.py index f7e2269c..84978b04 100644 --- a/benchmark/longbench/create_huggingface_dataset.py +++ b/benchmark/longbench/create_huggingface_dataset.py @@ -123,15 +123,27 @@ if task == "trec": dataset = dataset.map( - lambda x: {"input": question_template[task].format(input=x["input"].removesuffix("Type:"))} + lambda x: { + "input": question_template[task].format( + input=x["input"].removesuffix("Type:") + ) + } ) elif task == "triviaqa": dataset = dataset.map( - lambda x: {"input": question_template[task].format(input=x["input"].removesuffix("Answer:"))} + lambda x: { + "input": question_template[task].format( + input=x["input"].removesuffix("Answer:") + ) + } ) elif task == "samsum": dataset = dataset.map( - lambda x: {"input": question_template[task].format(input=x["input"].removesuffix("Summary:"))} + lambda x: { + "input": question_template[task].format( + input=x["input"].removesuffix("Summary:") + ) + } ) else: dataset = dataset.map(lambda x: {"input": question_template[task].format(**x)}) @@ -170,15 +182,27 @@ if task == "trec": dataset = dataset.map( - lambda x: {"input": question_template[task].format(input=x["input"].removesuffix("Type:"))} + lambda x: { + "input": question_template[task].format( + input=x["input"].removesuffix("Type:") + ) + } ) elif task == "triviaqa": dataset = dataset.map( - lambda x: {"input": question_template[task].format(input=x["input"].removesuffix("Answer:"))} + lambda x: { + "input": question_template[task].format( + input=x["input"].removesuffix("Answer:") + ) + } ) elif task == "samsum": dataset = dataset.map( - lambda x: {"input": question_template[task].format(input=x["input"].removesuffix("Summary:"))} + lambda x: { + "input": question_template[task].format( + input=x["input"].removesuffix("Summary:") + ) + } ) else: dataset = dataset.map(lambda x: {"input": question_template[task].format(**x)}) @@ -194,4 +218,6 @@ # Push to hub dataset = Dataset.from_pandas(df) - dataset.push_to_hub("xAlg-AI/att-hub-longbench", config_name=f"{task}_e", split="test") + dataset.push_to_hub( + "xAlg-AI/att-hub-longbench", config_name=f"{task}_e", split="test" + ) diff --git a/benchmark/longbench/longbench.py b/benchmark/longbench/longbench.py index 081fa6fa..d2edc2ef 100644 --- a/benchmark/longbench/longbench.py +++ b/benchmark/longbench/longbench.py @@ -33,36 +33,64 @@ class LongBench(Benchmark): # All available LongBench datasets (22 standard + 13 extended) all_datasets: List[str] = [ # Standard LongBench datasets - "narrativeqa", "qasper", "multifieldqa_en", "multifieldqa_zh", - "hotpotqa", "2wikimqa", "musique", "dureader", "gov_report", - "qmsum", "multi_news", "vcsum", "trec", "triviaqa", "samsum", - "lsht", "passage_count", "passage_retrieval_en", - "passage_retrieval_zh", "lcc", "repobench-p", + "narrativeqa", + "qasper", + "multifieldqa_en", + "multifieldqa_zh", + "hotpotqa", + "2wikimqa", + "musique", + "dureader", + "gov_report", + "qmsum", + "multi_news", + "vcsum", + "trec", + "triviaqa", + "samsum", + "lsht", + "passage_count", + "passage_retrieval_en", + "passage_retrieval_zh", + "lcc", + "repobench-p", # LongBench-E (extended) datasets with longer contexts - "qasper_e", "multifieldqa_en_e", "hotpotqa_e", "2wikimqa_e", - "gov_report_e", "multi_news_e", "trec_e", "triviaqa_e", - "samsum_e", "passage_count_e", "passage_retrieval_en_e", - "lcc_e", "repobench-p_e" + "qasper_e", + "multifieldqa_en_e", + "hotpotqa_e", + "2wikimqa_e", + "gov_report_e", + "multi_news_e", + "trec_e", + "triviaqa_e", + "samsum_e", + "passage_count_e", + "passage_retrieval_en_e", + "lcc_e", + "repobench-p_e", ] - + benchmark_name: str = "longbench" huggingface_dataset_id: str = "Xnhyacinth/LongBench" def _load_datasets(self) -> pd.DataFrame: """Load LongBench datasets by individual configs. - + LongBench requires loading each subset as a separate config. - + Returns: Combined pandas DataFrame with all samples from subsets_to_run. """ print(f"Loading LongBench datasets: {self.subsets_to_run}") dfs = [] - + for subset in self.subsets_to_run: try: from datasets import load_dataset - subset_dataset = load_dataset(self.huggingface_dataset_id, subset, split="test") + + subset_dataset = load_dataset( + self.huggingface_dataset_id, subset, split="test" + ) subset_df = subset_dataset.to_pandas() subset_df["task"] = subset # Ensure task column exists dfs.append(subset_df) @@ -70,12 +98,13 @@ def _load_datasets(self) -> pd.DataFrame: except Exception as subset_error: print(f" โŒ Failed to load {subset}: {str(subset_error)}") continue - + if not dfs: raise Exception("No LongBench subsets could be loaded successfully") - + # Combine all subset DataFrames import pandas as pd + combined_df = pd.concat(dfs, ignore_index=True) print(f"Combined {len(combined_df)} total samples from {len(dfs)} subsets") return combined_df @@ -104,35 +133,39 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: task_scores: Dict[str, Any] = {} standard_scores: List[float] = [] extended_scores: Dict[str, List[float]] = {"0-4k": [], "4-8k": [], "8k+": []} - + for task_name, task_df in task_groups: try: if task_name.endswith("_e"): # Extended dataset - use calculate_metrics_e for length-based breakdown length_scores: Dict[str, float] = calculate_metrics_e(task_df) task_scores[task_name] = length_scores - + # Accumulate extended scores for overall calculation for length_range in extended_scores: if length_range in length_scores: - extended_scores[length_range].append(length_scores[length_range]) + extended_scores[length_range].append( + length_scores[length_range] + ) else: # Standard dataset - use calculate_metrics score: float = calculate_metrics(task_df) task_scores[task_name] = score standard_scores.append(score) - + except Exception as e: print(f"Error evaluating task {task_name}: {str(e)}") task_scores[task_name] = {"error": str(e)} # Compute overall metrics overall_metrics: Dict[str, Any] = {"task_scores": task_scores} - + # Overall score for standard datasets if standard_scores: - overall_metrics["standard_overall_score"] = round(sum(standard_scores) / len(standard_scores), 2) - + overall_metrics["standard_overall_score"] = round( + sum(standard_scores) / len(standard_scores), 2 + ) + # Overall scores for extended datasets by length range if any(extended_scores.values()): extended_overall: Dict[str, float] = {} @@ -141,21 +174,25 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: extended_overall[length_range] = round(sum(scores) / len(scores), 2) if extended_overall: overall_metrics["extended_overall_scores"] = extended_overall - + # Compute grand overall score if we have both standard and extended results all_scores: List[float] = standard_scores.copy() for scores in extended_scores.values(): all_scores.extend(scores) - + if all_scores: - overall_metrics["overall_score"] = round(sum(all_scores) / len(all_scores), 2) - + overall_metrics["overall_score"] = round( + sum(all_scores) / len(all_scores), 2 + ) + # Add summary statistics overall_metrics["summary"] = { "total_tasks": len(task_scores), - "standard_tasks": len([t for t in task_scores.keys() if not t.endswith("_e")]), + "standard_tasks": len( + [t for t in task_scores.keys() if not t.endswith("_e")] + ), "extended_tasks": len([t for t in task_scores.keys() if t.endswith("_e")]), - "total_samples": len(results_df) + "total_samples": len(results_df), } - - return overall_metrics \ No newline at end of file + + return overall_metrics diff --git a/benchmark/longbenchv2/__init__.py b/benchmark/longbenchv2/__init__.py index b829ae7c..087f8627 100644 --- a/benchmark/longbenchv2/__init__.py +++ b/benchmark/longbenchv2/__init__.py @@ -8,4 +8,4 @@ from .calculate_metrics import calculate_metrics from .longbenchv2 import LongBenchv2 -__all__ = ["calculate_metrics", "LongBenchv2"] \ No newline at end of file +__all__ = ["calculate_metrics", "LongBenchv2"] diff --git a/benchmark/longbenchv2/calculate_metrics.py b/benchmark/longbenchv2/calculate_metrics.py index f85eebb3..71e91710 100644 --- a/benchmark/longbenchv2/calculate_metrics.py +++ b/benchmark/longbenchv2/calculate_metrics.py @@ -29,7 +29,9 @@ def scorer(predictions, answers, lengths, difficulties): compensated = False easy, hard, short, medium, long = 0, 0, 0, 0, 0 easy_acc, hard_acc, short_acc, medium_acc, long_acc = 0, 0, 0, 0, 0 - for pred, answer, length, difficulty in zip(predictions, answers, lengths, difficulties): + for pred, answer, length, difficulty in zip( + predictions, answers, lengths, difficulties + ): acc = int(extract_answer(pred) == answer) if compensated and pred["pred"] is None: acc = 0.25 # type:ignore[assignment] diff --git a/benchmark/longbenchv2/create_huggingface_dataset.py b/benchmark/longbenchv2/create_huggingface_dataset.py index 95c4b45a..e261342a 100644 --- a/benchmark/longbenchv2/create_huggingface_dataset.py +++ b/benchmark/longbenchv2/create_huggingface_dataset.py @@ -31,7 +31,9 @@ # Longbench-v2 for task in ["0shot", "cot"]: dataset = load_dataset("THUDM/LongBench-v2", split="train") - dataset = dataset.map(lambda x: {"context": context_prefix[task].format(context=x["context"].strip())}) + dataset = dataset.map( + lambda x: {"context": context_prefix[task].format(context=x["context"].strip())} + ) dataset = dataset.map( lambda x: { "question": question_template[task].format( diff --git a/benchmark/longbenchv2/longbenchv2.py b/benchmark/longbenchv2/longbenchv2.py index 01f56f61..566338f6 100644 --- a/benchmark/longbenchv2/longbenchv2.py +++ b/benchmark/longbenchv2/longbenchv2.py @@ -26,29 +26,29 @@ class LongBenchv2(Benchmark): """ # All available LongBenchv2 datasets - all_datasets: List[str] = [ - "0shot", - "cot" - ] - + all_datasets: List[str] = ["0shot", "cot"] + benchmark_name: str = "longbenchv2" huggingface_dataset_id: str = "Xnhyacinth/LongBench-v2" def _load_datasets(self) -> pd.DataFrame: """Load LongBenchv2 datasets by individual configs. - + LongBenchv2 requires loading each subset as a separate config. - + Returns: Combined pandas DataFrame with all samples from subsets_to_run. """ print(f"Loading LongBenchv2 datasets: {self.subsets_to_run}") dfs = [] - + for subset in self.subsets_to_run: try: from datasets import load_dataset - subset_dataset = load_dataset(self.huggingface_dataset_id, subset, split="test") + + subset_dataset = load_dataset( + self.huggingface_dataset_id, subset, split="test" + ) subset_df = subset_dataset.to_pandas() subset_df["task"] = subset # Ensure task column exists dfs.append(subset_df) @@ -56,12 +56,13 @@ def _load_datasets(self) -> pd.DataFrame: except Exception as subset_error: print(f" โŒ Failed to load {subset}: {str(subset_error)}") continue - + if not dfs: raise Exception("No LongBenchv2 subsets could be loaded successfully") - + # Combine all subset DataFrames import pandas as pd + combined_df = pd.concat(dfs, ignore_index=True) print(f"Combined {len(combined_df)} total samples from {len(dfs)} subsets") return combined_df @@ -90,20 +91,20 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: task_groups = results_df.groupby("task") task_scores: Dict[str, Any] = {} all_scores: List[float] = [] - + for task_name, task_df in task_groups: try: # Use the calculate_metrics function from HashAttention evaluation scores = calculate_metrics(task_df) - + # Parse the scores string to extract overall accuracy if len(scores) >= 2: - overall_score_str = scores[1].split('\t')[0] + overall_score_str = scores[1].split("\t")[0] try: overall_score = float(overall_score_str) task_scores[task_name] = { "overall_accuracy": overall_score, - "detailed_scores": scores + "detailed_scores": scores, } all_scores.append(overall_score) print(f" โœ“ {task_name}: {overall_score:.1f}%") @@ -111,21 +112,21 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: task_scores[task_name] = {"error": "Could not parse score"} else: task_scores[task_name] = {"error": "No scores returned"} - + except Exception as e: print(f"Error evaluating task {task_name}: {str(e)}") task_scores[task_name] = {"error": str(e)} # Compute overall metrics overall_score = sum(all_scores) / len(all_scores) if all_scores else 0.0 - + overall_metrics: Dict[str, Any] = { "overall_score": round(overall_score, 1), "task_scores": task_scores, "summary": { "total_tasks": len(task_scores), - "total_samples": len(results_df) - } + "total_samples": len(results_df), + }, } - - return overall_metrics \ No newline at end of file + + return overall_metrics diff --git a/benchmark/loogle/calculate_metrics.py b/benchmark/loogle/calculate_metrics.py index 7deb02bd..ab3bdd48 100644 --- a/benchmark/loogle/calculate_metrics.py +++ b/benchmark/loogle/calculate_metrics.py @@ -76,7 +76,10 @@ def wrapped_metric(answer, predicted_answer): try: return metric_fn(answer, predicted_answer) except Exception as e: - print(f"Cannot calculate metric: {e}" f" on answer:{answer} and predicted_answer:{predicted_answer}") + print( + f"Cannot calculate metric: {e}" + f" on answer:{answer} and predicted_answer:{predicted_answer}" + ) return {key: 0.0 for key in metric_fn("Hi there", "hi there")} return wrapped_metric @@ -93,21 +96,36 @@ def calculate_metrics(df: pd.DataFrame) -> dict: ("exact", get_exact_match), ("partial", get_partial_match), ]: - match, count = zip(*df_task.apply(lambda x: metric_fn(x["answer"], x["predicted_answer"]), axis=1)) + match, count = zip( + *df_task.apply( + lambda x: metric_fn(x["answer"], x["predicted_answer"]), axis=1 + ) + ) scores[task][f"{prefix}_match"] = round(sum(match) / sum(count), 4) else: - df["predicted_answer"] = df["predicted_answer"].apply(lambda x: x if isinstance(x, str) else "") + df["predicted_answer"] = df["predicted_answer"].apply( + lambda x: x if isinstance(x, str) else "" + ) for metric_fn in [get_bleu_score, get_rouge_score, get_meteor_score]: # type: ignore metric_fn = try_except_metric(metric_fn) - metric_scores = [metric_fn(row["answer"], row["predicted_answer"]) for _, row in df_task.iterrows()] + metric_scores = [ + metric_fn(row["answer"], row["predicted_answer"]) + for _, row in df_task.iterrows() + ] scores[task].update(pd.DataFrame(metric_scores).mean().to_dict()) # BERT scores (batched) scores[task]["bert"] = ( - score(df_task["answer"].to_list(), df_task["predicted_answer"].to_list(), lang="EN")[1].mean().item() + score( + df_task["answer"].to_list(), + df_task["predicted_answer"].to_list(), + lang="EN", + )[1] + .mean() + .item() ) return scores diff --git a/benchmark/loogle/create_huggingface_dataset.py b/benchmark/loogle/create_huggingface_dataset.py index ef2fd15b..78eb732e 100644 --- a/benchmark/loogle/create_huggingface_dataset.py +++ b/benchmark/loogle/create_huggingface_dataset.py @@ -30,19 +30,30 @@ } # Source: https://github.com/bigai-nlco/LooGLE/blob/main/config/task2maxlen.json -max_new_tokens = {"shortdep_qa": 300, "longdep_qa": 500, "longdep_summarization": 500, "shortdep_cloze": 50} +max_new_tokens = { + "shortdep_qa": 300, + "longdep_qa": 500, + "longdep_summarization": 500, + "shortdep_cloze": 50, +} for task in ["shortdep_qa", "longdep_qa", "shortdep_cloze", "longdep_summarization"]: - df = load_dataset("bigainlco/LooGLE", task, split="test", trust_remote_code=True).to_pandas() + df = load_dataset( + "bigainlco/LooGLE", task, split="test", trust_remote_code=True + ).to_pandas() if task == "longdep_summarization": df["question"] = "" df = df.rename(columns={"output": "answer", "input": "context"}) else: - df["qa_pairs"] = df["qa_pairs"].apply(lambda x: eval(x) if x != "none" else [{"Q": "", "A": "", "S": [""]}]) + df["qa_pairs"] = df["qa_pairs"].apply( + lambda x: eval(x) if x != "none" else [{"Q": "", "A": "", "S": [""]}] + ) df = df.explode("qa_pairs") - df = pd.concat([df.drop(["qa_pairs"], axis=1), df["qa_pairs"].apply(pd.Series)], axis=1) + df = pd.concat( + [df.drop(["qa_pairs"], axis=1), df["qa_pairs"].apply(pd.Series)], axis=1 + ) df = df.rename(columns={"A": "answer", "Q": "question", "input": "context"}) if task == "shortdep_cloze": df["answer"] = df["answer"].apply(json.dumps, ensure_ascii=False) diff --git a/benchmark/loogle/loogle.py b/benchmark/loogle/loogle.py index d66b77ba..9c311a9b 100644 --- a/benchmark/loogle/loogle.py +++ b/benchmark/loogle/loogle.py @@ -31,27 +31,30 @@ class Loogle(Benchmark): "shortdep_qa", "longdep_qa", "shortdep_cloze", - "longdep_summarization" + "longdep_summarization", ] - + benchmark_name: str = "loogle" huggingface_dataset_id: str = "simonjegou/loogle" def _load_datasets(self) -> pd.DataFrame: """Load Loogle datasets by individual configs. - + Loogle requires loading each subset as a separate config. - + Returns: Combined pandas DataFrame with all samples from subsets_to_run. """ print(f"Loading Loogle datasets: {self.subsets_to_run}") dfs = [] - + for subset in self.subsets_to_run: try: from datasets import load_dataset - subset_dataset = load_dataset(self.huggingface_dataset_id, subset, split="test") + + subset_dataset = load_dataset( + self.huggingface_dataset_id, subset, split="test" + ) subset_df = subset_dataset.to_pandas() subset_df["task"] = subset # Ensure task column exists dfs.append(subset_df) @@ -59,12 +62,13 @@ def _load_datasets(self) -> pd.DataFrame: except Exception as subset_error: print(f" โŒ Failed to load {subset}: {str(subset_error)}") continue - + if not dfs: raise Exception("No Loogle subsets could be loaded successfully") - + # Combine all subset DataFrames import pandas as pd + combined_df = pd.concat(dfs, ignore_index=True) print(f"Combined {len(combined_df)} total samples from {len(dfs)} subsets") return combined_df @@ -88,7 +92,7 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: # Use the calculate_metrics function from HashAttention evaluation task_scores: Dict[str, Dict[str, float]] = calculate_metrics(results_df) - + # Compute overall score by averaging task scores all_scores: List[float] = [] for task, scores in task_scores.items(): @@ -101,16 +105,16 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: # Fallback to first available metric elif scores: all_scores.append(list(scores.values())[0]) - + overall_score = sum(all_scores) / len(all_scores) if all_scores else 0.0 - + overall_metrics: Dict[str, Any] = { "overall_score": round(overall_score, 4), "task_scores": task_scores, "summary": { "total_tasks": len(task_scores), - "total_samples": len(results_df) - } + "total_samples": len(results_df), + }, } - - return overall_metrics \ No newline at end of file + + return overall_metrics diff --git a/benchmark/mock_benchmark/__init__.py b/benchmark/mock_benchmark/__init__.py index 0774219f..09d3ed56 100644 --- a/benchmark/mock_benchmark/__init__.py +++ b/benchmark/mock_benchmark/__init__.py @@ -1,9 +1,7 @@ - - """ Mock benchmark module for testing and demonstration purposes. """ from .mock_benchmark import MockBenchmark -__all__ = ["MockBenchmark"] \ No newline at end of file +__all__ = ["MockBenchmark"] diff --git a/benchmark/mock_benchmark/mock_benchmark.py b/benchmark/mock_benchmark/mock_benchmark.py index a069b919..2f0108d0 100644 --- a/benchmark/mock_benchmark/mock_benchmark.py +++ b/benchmark/mock_benchmark/mock_benchmark.py @@ -27,11 +27,13 @@ class MockBenchmark(Benchmark): # Class attributes required by base Benchmark class all_datasets: List[str] = ["reading_comprehension"] benchmark_name: str = "mock_benchmark" - huggingface_dataset_id: str = "mock/dataset" # Not actually used since we override _load_datasets + huggingface_dataset_id: str = ( + "mock/dataset" # Not actually used since we override _load_datasets + ) def _load_datasets(self) -> pd.DataFrame: """Load mock dataset with hardcoded samples. - + Returns: DataFrame containing 5 mock samples with context, question, and answers. """ @@ -51,7 +53,6 @@ def _load_datasets(self) -> pd.DataFrame: in their leaves, where specialized organelles called chloroplasts contain the chlorophyll necessary for the process. """.strip(), - "history_context": """ The Renaissance was a period of cultural, artistic, and intellectual revival that began in Italy during the 14th century and spread throughout Europe. @@ -67,7 +68,6 @@ def _load_datasets(self) -> pd.DataFrame: laid the foundation for the Scientific Revolution and the Enlightenment that would follow. """.strip(), - "geography_context": """ The Amazon rainforest, often called the "lungs of the Earth," is the world's largest tropical rainforest. Located primarily in Brazil, it also extends @@ -81,7 +81,7 @@ def _load_datasets(self) -> pd.DataFrame: drainage basin. Unfortunately, the rainforest faces threats from deforestation, mining, and climate change, making its conservation critical for the health of our planet. - """.strip() + """.strip(), } # Create sample data - 5 samples total, 2 sharing the same context @@ -89,46 +89,50 @@ def _load_datasets(self) -> pd.DataFrame: { "context": contexts["science_context"], "question": "What are the two main stages of photosynthesis?", - "answers": ["light-dependent reactions and light-independent reactions", - "light-dependent reactions and Calvin cycle"], - "task": "reading_comprehension" + "answers": [ + "light-dependent reactions and light-independent reactions", + "light-dependent reactions and Calvin cycle", + ], + "task": "reading_comprehension", }, { "context": contexts["science_context"], # Same context as sample 1 "question": "What gas is produced as a byproduct of photosynthesis?", "answers": ["oxygen"], - "task": "reading_comprehension" + "task": "reading_comprehension", }, { "context": contexts["history_context"], "question": "In which century did the Renaissance begin?", "answers": ["14th century", "14th"], - "task": "reading_comprehension" + "task": "reading_comprehension", }, { "context": contexts["geography_context"], "question": "Why is the Amazon rainforest called the 'lungs of the Earth'?", - "answers": ["because it absorbs carbon dioxide and produces oxygen", - "it regulates global climate by absorbing CO2 and producing oxygen"], - "task": "reading_comprehension" + "answers": [ + "because it absorbs carbon dioxide and produces oxygen", + "it regulates global climate by absorbing CO2 and producing oxygen", + ], + "task": "reading_comprehension", }, { "context": contexts["geography_context"], "question": "Which river flows through the Amazon rainforest?", "answers": ["Amazon River", "the Amazon River"], - "task": "reading_comprehension" - } + "task": "reading_comprehension", + }, ] # Convert to DataFrame df: pd.DataFrame = pd.DataFrame(sample_data) - + # Add sample IDs for tracking df["sample_id"] = range(1, len(df) + 1) - + print(f"Loaded {len(df)} mock samples") print(f"Unique contexts: {df['context'].nunique()}") - + return df def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: @@ -159,32 +163,38 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: predicted_answer: str = str(row["predicted_answer"]).strip().lower() ground_truth_answers: List[str] = row["answers"] sample_id: int = row["sample_id"] - + # Check if prediction matches any ground truth answer is_correct: bool = False for gt_answer in ground_truth_answers: gt_answer_normalized: str = str(gt_answer).strip().lower() - + # Check exact match or substring match - if (predicted_answer == gt_answer_normalized or - gt_answer_normalized in predicted_answer): + if ( + predicted_answer == gt_answer_normalized + or gt_answer_normalized in predicted_answer + ): is_correct = True break - + if is_correct: correct_predictions += 1 - - sample_scores.append({ - "sample_id": sample_id, - "question": row["question"], - "predicted_answer": row["predicted_answer"], - "ground_truth": ground_truth_answers, - "correct": is_correct - }) + + sample_scores.append( + { + "sample_id": sample_id, + "question": row["question"], + "predicted_answer": row["predicted_answer"], + "ground_truth": ground_truth_answers, + "correct": is_correct, + } + ) # Calculate metrics - accuracy: float = correct_predictions / total_samples if total_samples > 0 else 0.0 - + accuracy: float = ( + correct_predictions / total_samples if total_samples > 0 else 0.0 + ) + metrics: Dict[str, Any] = { "accuracy": round(accuracy, 3), "correct_predictions": correct_predictions, @@ -194,8 +204,8 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: "benchmark": self.benchmark_name, "task": "reading_comprehension", "unique_contexts": results_df["context"].nunique(), - "evaluation_method": "exact_match_and_substring" - } + "evaluation_method": "exact_match_and_substring", + }, } - return metrics \ No newline at end of file + return metrics diff --git a/benchmark/ruler/calculate_metrics.py b/benchmark/ruler/calculate_metrics.py index 16d1b924..4fa78ec9 100644 --- a/benchmark/ruler/calculate_metrics.py +++ b/benchmark/ruler/calculate_metrics.py @@ -9,7 +9,12 @@ def string_match_part(preds, refs): score = ( - sum([max([1.0 if r.lower() in pred.lower() else 0.0 for r in ref]) for pred, ref in zip(preds, refs)]) + sum( + [ + max([1.0 if r.lower() in pred.lower() else 0.0 for r in ref]) + for pred, ref in zip(preds, refs) + ] + ) / len(preds) * 100 ) @@ -19,7 +24,10 @@ def string_match_part(preds, refs): def string_match_all(preds, refs): score = ( sum( - [sum([1.0 if r.lower() in pred.lower() else 0.0 for r in ref]) / len(ref) for pred, ref in zip(preds, refs)] + [ + sum([1.0 if r.lower() in pred.lower() else 0.0 for r in ref]) / len(ref) + for pred, ref in zip(preds, refs) + ] ) / len(preds) * 100 @@ -31,7 +39,9 @@ def calculate_metrics(df: pd.DataFrame) -> dict: scores = {} np_pattern = re.compile(r"[\x00-\x1f]") - df["predicted_answer"] = df["predicted_answer"].apply(lambda x: np_pattern.sub("", x.strip()).strip()) + df["predicted_answer"] = df["predicted_answer"].apply( + lambda x: np_pattern.sub("", x.strip()).strip() + ) for task, df_task in df.groupby("task"): task_category = task.split("_")[0] diff --git a/benchmark/ruler/create_huggingface_dataset.py b/benchmark/ruler/create_huggingface_dataset.py index b31f14bf..74628967 100644 --- a/benchmark/ruler/create_huggingface_dataset.py +++ b/benchmark/ruler/create_huggingface_dataset.py @@ -13,7 +13,9 @@ QUESTION_PATTERNS = { "niah": re.compile(r"What (?:is|are all) the special magic"), "vt": re.compile(r"Question: Find all variables that are assigned the value"), - "cwe": re.compile(r"Question: What are the 10 most common words in the above list\?"), + "cwe": re.compile( + r"Question: What are the 10 most common words in the above list\?" + ), "fwe": re.compile(r"Question: Do not provide any explanation\."), "qa": re.compile(r"Answer the question based on the given documents\."), } @@ -41,7 +43,9 @@ def get_dataframe(path): Parse the data from the provided path and return a DataFrame with the context, question, answers and task """ - assert re.match(r".*\/\d+$", str(path)), "The path should must ends with the context length (e.g. with /4096)" + assert re.match( + r".*\/\d+$", str(path) + ), "The path should must ends with the context length (e.g. with /4096)" df_list = [] for task_path in Path(path).glob("**/*.jsonl"): @@ -60,21 +64,27 @@ def split_context_question(text): question, answer = qa[:idx], qa[idx:] return context, question, answer - df["context"], df["question"], df["answer_prefix"] = zip(*df["input"].apply(split_context_question)) + df["context"], df["question"], df["answer_prefix"] = zip( + *df["input"].apply(split_context_question) + ) df["task"] = task df["max_new_tokens"] = MAX_NEW_TOKENS[task.split("_")[0]] df_list.append(df) # Concatenate all the dataframes df = pd.concat(df_list) - df = df[["context", "question", "answer_prefix", "outputs", "task", "max_new_tokens"]] + df = df[ + ["context", "question", "answer_prefix", "outputs", "task", "max_new_tokens"] + ] df = df.rename(columns={"outputs": "answer"}).reset_index(drop=True) return df if __name__ == "__main__": - data_dir = Path("/mnt/workspace/projects/RULER/scripts/data/data/") # output of the generate.sh script + data_dir = Path( + "/mnt/workspace/projects/RULER/scripts/data/data/" + ) # output of the generate.sh script repo_id = "simonjegou/ruler" # Loop over all the context lengths diff --git a/benchmark/ruler/ruler.py b/benchmark/ruler/ruler.py index afe770d5..1035c666 100644 --- a/benchmark/ruler/ruler.py +++ b/benchmark/ruler/ruler.py @@ -27,31 +27,29 @@ class Ruler(Benchmark): """ # All available Ruler datasets (context lengths) - all_datasets: List[str] = [ - "4096", - "8192", - "16384", - "32768" - ] - + all_datasets: List[str] = ["4096", "8192", "16384", "32768"] + benchmark_name: str = "ruler" huggingface_dataset_id: str = "simonjegou/ruler" def _load_datasets(self) -> pd.DataFrame: """Load Ruler datasets by individual configs. - + Ruler requires loading each context length as a separate config. - + Returns: Combined pandas DataFrame with all samples from subsets_to_run. """ print(f"Loading Ruler datasets: {self.subsets_to_run}") dfs = [] - + for subset in self.subsets_to_run: try: from datasets import load_dataset - subset_dataset = load_dataset(self.huggingface_dataset_id, subset, split="test") + + subset_dataset = load_dataset( + self.huggingface_dataset_id, subset, split="test" + ) subset_df = subset_dataset.to_pandas() # Add context length as a column for analysis subset_df["context_length"] = subset @@ -60,12 +58,13 @@ def _load_datasets(self) -> pd.DataFrame: except Exception as subset_error: print(f" โŒ Failed to load {subset}: {str(subset_error)}") continue - + if not dfs: raise Exception("No Ruler subsets could be loaded successfully") - + # Combine all subset DataFrames import pandas as pd + combined_df = pd.concat(dfs, ignore_index=True) print(f"Combined {len(combined_df)} total samples from {len(dfs)} subsets") return combined_df @@ -91,15 +90,15 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: # Use the calculate_metrics function from HashAttention evaluation task_scores: Dict[str, Dict[str, float]] = calculate_metrics(results_df) - + # Extract string_match scores and compute overall all_scores: List[float] = [] for task, scores in task_scores.items(): if "string_match" in scores: all_scores.append(scores["string_match"]) - + overall_score = sum(all_scores) / len(all_scores) if all_scores else 0.0 - + # Group by context length if available context_length_scores: Dict[str, float] = {} if "context_length" in results_df.columns: @@ -107,9 +106,19 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: length_df = results_df[results_df["context_length"] == context_length] if len(length_df) > 0: length_scores = calculate_metrics(length_df) - length_overall = sum(score.get("string_match", 0) for score in length_scores.values()) / len(length_scores) if length_scores else 0.0 - context_length_scores[str(context_length)] = round(length_overall, 2) - + length_overall = ( + sum( + score.get("string_match", 0) + for score in length_scores.values() + ) + / len(length_scores) + if length_scores + else 0.0 + ) + context_length_scores[str(context_length)] = round( + length_overall, 2 + ) + overall_metrics: Dict[str, Any] = { "overall_score": round(overall_score, 2), "task_scores": task_scores, @@ -117,8 +126,8 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: "summary": { "total_tasks": len(task_scores), "total_samples": len(results_df), - "context_lengths": list(context_length_scores.keys()) - } + "context_lengths": list(context_length_scores.keys()), + }, } - - return overall_metrics \ No newline at end of file + + return overall_metrics diff --git a/benchmark/scripts/benchmark.py b/benchmark/scripts/benchmark.py index 289fa0f1..e69e0802 100644 --- a/benchmark/scripts/benchmark.py +++ b/benchmark/scripts/benchmark.py @@ -19,9 +19,12 @@ from benchmark.executor import BenchmarkExecutor from benchmark.executor_config import BenchmarkConfig, AdapterConfig -from sparse_attention_hub.sparse_attention.research_attention import ResearchAttentionConfig +from sparse_attention_hub.sparse_attention.research_attention import ( + ResearchAttentionConfig, +) from sparse_attention_hub.sparse_attention.research_attention.maskers.fixed.implementations import ( - LocalMaskerConfig, SinkMaskerConfig + LocalMaskerConfig, + SinkMaskerConfig, ) # ============================================================================ @@ -29,80 +32,63 @@ # ============================================================================ # GPU Configuration -GPUS = [0,2,7] # Use all available GPUs +GPUS = [0, 2, 7] # Use all available GPUs MAX_CONCURRENT_RUNS = 3 # One per GPU # Model List MODELS = [ - "microsoft/Phi-4-mini-instruct", - "meta-llama/Llama-3.2-1B-Instruct", + "microsoft/Phi-4-mini-instruct", + "meta-llama/Llama-3.2-1B-Instruct", ] # Sparse Attention Configurations SPARSE_CONFIGS = [ # Dense baseline (no sparse attention) ("dense", None), - # StreamingLLM configurations - ("streaming_conservative", ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=4), - LocalMaskerConfig(window_size=16) - ])), + ( + "streaming_conservative", + ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=4), + LocalMaskerConfig(window_size=16), + ] + ), + ), ] # Benchmark List # 1. InfiniteBench - using passkey task infinite_bench_config = BenchmarkConfig( - benchmark_name="infinite_bench", - subsets=["passkey"] + benchmark_name="infinite_bench", subsets=["passkey"] ) # 2. Ruler - using 4096 context length -ruler_config = BenchmarkConfig( - benchmark_name="ruler", - subsets=["4096"] -) +ruler_config = BenchmarkConfig(benchmark_name="ruler", subsets=["4096"]) # 3. Loogle - using shortdep_qa task -loogle_config = BenchmarkConfig( - benchmark_name="loogle", - subsets=["shortdep_qa"] -) +loogle_config = BenchmarkConfig(benchmark_name="loogle", subsets=["shortdep_qa"]) # 4. ZeroScrolls - using gov_report task zero_scrolls_config = BenchmarkConfig( - benchmark_name="zero_scrolls", - subsets=["default"] + benchmark_name="zero_scrolls", subsets=["default"] ) # 5. LongBenchv2 - using 0shot task -longbenchv2_config = BenchmarkConfig( - benchmark_name="longbenchv2", - subsets=["0shot"] -) +longbenchv2_config = BenchmarkConfig(benchmark_name="longbenchv2", subsets=["0shot"]) # 6. AIME2024 - using single task -aime2024_config = BenchmarkConfig( - benchmark_name="aime2024", - subsets=["aime2024"] -) +aime2024_config = BenchmarkConfig(benchmark_name="aime2024", subsets=["aime2024"]) # 7. AIME2025 - using single task -aime2025_config = BenchmarkConfig( - benchmark_name="aime2025", - subsets=["aime2025"] -) +aime2025_config = BenchmarkConfig(benchmark_name="aime2025", subsets=["aime2025"]) # 8. LongBench (existing) - using narrativeqa task -longbench_config = BenchmarkConfig( - benchmark_name="longbench", - subsets=["narrativeqa"] -) +longbench_config = BenchmarkConfig(benchmark_name="longbench", subsets=["narrativeqa"]) # 9. Mock Benchmark (existing) - using single task mock_benchmark_config = BenchmarkConfig( - benchmark_name="mock_benchmark", - subsets=["reading_comprehension"] + benchmark_name="mock_benchmark", subsets=["reading_comprehension"] ) # List of all sample configurations @@ -115,7 +101,7 @@ aime2024_config, aime2025_config, longbench_config, - mock_benchmark_config + mock_benchmark_config, ] @@ -127,7 +113,7 @@ }, tokenizer_kwargs={ "padding_side": "left", - } + }, ) # Generation Parameters @@ -157,7 +143,7 @@ if __name__ == "__main__": print("๐Ÿš€ Starting Minimalistic Benchmark Suite") print("=" * 50) - + print(f"๐Ÿ”ง Configuration:") print(f" - GPUs: {GPUS}") print(f" - Models: {len(MODELS)}") @@ -174,25 +160,29 @@ print(f" - Benchmarks: {len(BENCHMARKS)}") for i, benchmark in enumerate(BENCHMARKS, 1): if benchmark.subsets: - print(f" {i}. {benchmark.benchmark_name}: {len(benchmark.subsets)} subsets") + print( + f" {i}. {benchmark.benchmark_name}: {len(benchmark.subsets)} subsets" + ) else: print(f" {i}. {benchmark.benchmark_name}: all subsets") print(f" - Max concurrent: {MAX_CONCURRENT_RUNS}") print(f" - Result dir: {RESULT_DIR}") print(f" - Resumability: {'enabled' if ENABLE_RESUMABILITY else 'disabled'}") - + # Calculate total combinations total_models = len(MODELS) total_configs = len(SPARSE_CONFIGS) total_benchmarks = sum(len(b.subsets) if b.subsets else 1 for b in BENCHMARKS) total_combinations = total_models * total_configs * total_benchmarks - + print(f"\n๐Ÿ“Š Experiment Matrix: {total_combinations} total combinations") print(f" - Models: {total_models}") print(f" - Sparse configs: {total_configs}") print(f" - Benchmark-subsets: {total_benchmarks}") - print(f" - Estimated time: {total_combinations * TIMEOUT_PER_BENCHMARK / 3600:.1f} hours (worst case)") - + print( + f" - Estimated time: {total_combinations * TIMEOUT_PER_BENCHMARK / 3600:.1f} hours (worst case)" + ) + # Create executor print(f"\n๐Ÿ”ง Initializing BenchmarkExecutor...") executor = BenchmarkExecutor( @@ -202,9 +192,9 @@ enable_resumability=ENABLE_RESUMABILITY, required_result_files=["raw_results.csv"], timeout_per_benchmark=TIMEOUT_PER_BENCHMARK, - verbose=True + verbose=True, ) - + # Run benchmarks print(f"\n๐ŸŽฏ Running Benchmark Matrix...") try: @@ -214,9 +204,9 @@ benchmark_configs=BENCHMARKS, adapter_config=ADAPTER_CONFIG, generation_kwargs=GENERATION_KWARGS, - request_kwargs=REQUEST_KWARGS + request_kwargs=REQUEST_KWARGS, ) - + # Print summary print(f"\nโœ… Benchmark Execution Completed!") print(f" - Total: {results.progress.total_stubs}") @@ -224,10 +214,10 @@ print(f" - Failed: {results.progress.failed_stubs}") print(f" - Skipped: {results.progress.skipped_stubs}") print(f" - Results saved to: {RESULT_DIR}") - + except KeyboardInterrupt: print(f"\nโš ๏ธ Interrupted by user") print(f" Partial results in: {RESULT_DIR}") except Exception as e: print(f"\nโŒ Execution failed: {e}") - raise + raise diff --git a/benchmark/scripts/executor_example.py b/benchmark/scripts/executor_example.py index 092e4467..835581e9 100644 --- a/benchmark/scripts/executor_example.py +++ b/benchmark/scripts/executor_example.py @@ -20,12 +20,19 @@ from benchmark.executor import BenchmarkExecutor from benchmark.executor_config import BenchmarkConfig, AdapterConfig -from sparse_attention_hub.sparse_attention.research_attention import ResearchAttentionConfig +from sparse_attention_hub.sparse_attention.research_attention import ( + ResearchAttentionConfig, +) from sparse_attention_hub.sparse_attention.research_attention.maskers.fixed.implementations import ( - LocalMaskerConfig, SinkMaskerConfig, OracleTopKConfig, OracleTopPMaskerConfig + LocalMaskerConfig, + SinkMaskerConfig, + OracleTopKConfig, + OracleTopPMaskerConfig, ) from sparse_attention_hub.sparse_attention.research_attention.maskers.sampling.implementations import ( - AdaptiveSamplingMaskerConfig, RandomSamplingMaskerConfig, MagicPigConfig + AdaptiveSamplingMaskerConfig, + RandomSamplingMaskerConfig, + MagicPigConfig, ) # ============================================================================ @@ -40,121 +47,140 @@ # Model List MODELS = [ - "meta-llama/Llama-3.1-8B-Instruct", + "meta-llama/Llama-3.1-8B-Instruct", ] # Sparse Attention Configurations SPARSE_CONFIGS = [ # Dense baseline (no sparse attention) ("dense", None), - # StreamingLLM configurations - ("streaming_conservative", ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=128), - LocalMaskerConfig(window_size=INTENDED_SPARSITY) - ])), - #Oracle-TopK - ("streaming_oracle_topk", ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=128), - LocalMaskerConfig(window_size=128), - OracleTopKConfig(heavy_size=INTENDED_SPARSITY) - ])), + ( + "streaming_conservative", + ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=128), + LocalMaskerConfig(window_size=INTENDED_SPARSITY), + ] + ), + ), + # Oracle-TopK + ( + "streaming_oracle_topk", + ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=128), + LocalMaskerConfig(window_size=128), + OracleTopKConfig(heavy_size=INTENDED_SPARSITY), + ] + ), + ), # Oracle-TopP - ("streaming_oracle_topp", ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=128), - LocalMaskerConfig(window_size=128), - OracleTopPMaskerConfig(top_p=0.85) - ])), + ( + "streaming_oracle_topp", + ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=128), + LocalMaskerConfig(window_size=128), + OracleTopPMaskerConfig(top_p=0.85), + ] + ), + ), # Adaptive Sampling - ("streaming_adaptive_sampling", ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=128), - LocalMaskerConfig(window_size=128), - OracleTopKConfig(heavy_size=128), - AdaptiveSamplingMaskerConfig(base_rate_sampling=0.05, epsilon=0.25, delta=0.25, init_offset=128, local_offset=128) - ])), - # Random Sampling - ("streaming_random_sampling", ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=128), - LocalMaskerConfig(window_size=128), - RandomSamplingMaskerConfig(sampling_rate=0.1) - ])), - # MagicPig - ("streaming_magicpig", ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=128), - LocalMaskerConfig(window_size=128), - MagicPigConfig(lsh_l=8, lsh_k=8) - ])), + ( + "streaming_adaptive_sampling", + ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=128), + LocalMaskerConfig(window_size=128), + OracleTopKConfig(heavy_size=128), + AdaptiveSamplingMaskerConfig( + base_rate_sampling=0.05, + epsilon=0.25, + delta=0.25, + init_offset=128, + local_offset=128, + ), + ] + ), + ), + # Random Sampling + ( + "streaming_random_sampling", + ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=128), + LocalMaskerConfig(window_size=128), + RandomSamplingMaskerConfig(sampling_rate=0.1), + ] + ), + ), + # MagicPig + ( + "streaming_magicpig", + ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=128), + LocalMaskerConfig(window_size=128), + MagicPigConfig(lsh_l=8, lsh_k=8), + ] + ), + ), ] # Benchmark List # 1. InfiniteBench - using passkey task infinite_bench_config = BenchmarkConfig( - benchmark_name="infinite_bench", - subsets=["passkey"] + benchmark_name="infinite_bench", subsets=["passkey"] ) # 2. Ruler - using 4096 context length -ruler_config = BenchmarkConfig( - benchmark_name="ruler", - subsets=["4096"] -) +ruler_config = BenchmarkConfig(benchmark_name="ruler", subsets=["4096"]) # 3. Loogle - using shortdep_qa task loogle_config = BenchmarkConfig( benchmark_name="loogle", subsets=["shortdep_qa"], - #subsets=["longdep_qa"], - #subsets=["shortdep_cloze"], - #subsets=["longdep_summarization"], + # subsets=["longdep_qa"], + # subsets=["shortdep_cloze"], + # subsets=["longdep_summarization"], ) # 4. ZeroScrolls - using gov_report task zero_scrolls_config = BenchmarkConfig( - benchmark_name="zero_scrolls", - subsets=["default"] + benchmark_name="zero_scrolls", subsets=["default"] ) # 5. LongBenchv2 - using 0shot task -longbenchv2_config = BenchmarkConfig( - benchmark_name="longbenchv2", - subsets=["0shot"] -) +longbenchv2_config = BenchmarkConfig(benchmark_name="longbenchv2", subsets=["0shot"]) # 6. AIME2024 - using single task -aime2024_config = BenchmarkConfig( - benchmark_name="aime2024", - subsets=["aime2024"] -) +aime2024_config = BenchmarkConfig(benchmark_name="aime2024", subsets=["aime2024"]) # 7. AIME2025 - using single task -aime2025_config = BenchmarkConfig( - benchmark_name="aime2025", - subsets=["aime2025"] -) +aime2025_config = BenchmarkConfig(benchmark_name="aime2025", subsets=["aime2025"]) # 8. LongBench (existing) - using narrativeqa task longbench_config = BenchmarkConfig( - benchmark_name="longbench", - subsets=["passage_retrieval_en"] + benchmark_name="longbench", subsets=["passage_retrieval_en"] ) # 9. Mock Benchmark (existing) - using single task mock_benchmark_config = BenchmarkConfig( - benchmark_name="mock_benchmark", - subsets=["reading_comprehension"] + benchmark_name="mock_benchmark", subsets=["reading_comprehension"] ) # List of all sample configurations BENCHMARKS = [ - #infinite_bench_config, - #ruler_config, + # infinite_bench_config, + # ruler_config, loogle_config, - #zero_scrolls_config, - #longbenchv2_config, - #aime2024_config, - #aime2025_config, - #longbench_config, - #mock_benchmark_config + # zero_scrolls_config, + # longbenchv2_config, + # aime2024_config, + # aime2025_config, + # longbench_config, + # mock_benchmark_config ] @@ -167,7 +193,7 @@ }, tokenizer_kwargs={ "padding_side": "left", - } + }, ) # Generation Parameters @@ -196,7 +222,7 @@ if __name__ == "__main__": print("๐Ÿš€ Starting Minimalistic Benchmark Suite") print("=" * 50) - + print(f"๐Ÿ”ง Configuration:") print(f" - GPUs: {GPUS}") print(f" - Models: {len(MODELS)}") @@ -213,25 +239,29 @@ print(f" - Benchmarks: {len(BENCHMARKS)}") for i, benchmark in enumerate(BENCHMARKS, 1): if benchmark.subsets: - print(f" {i}. {benchmark.benchmark_name}: {len(benchmark.subsets)} subsets") + print( + f" {i}. {benchmark.benchmark_name}: {len(benchmark.subsets)} subsets" + ) else: print(f" {i}. {benchmark.benchmark_name}: all subsets") print(f" - Max concurrent: {MAX_CONCURRENT_RUNS}") print(f" - Result dir: {RESULT_DIR}") print(f" - Resumability: {'enabled' if ENABLE_RESUMABILITY else 'disabled'}") - + # Calculate total combinations total_models = len(MODELS) total_configs = len(SPARSE_CONFIGS) total_benchmarks = sum(len(b.subsets) if b.subsets else 1 for b in BENCHMARKS) total_combinations = total_models * total_configs * total_benchmarks - + print(f"\n๐Ÿ“Š Experiment Matrix: {total_combinations} total combinations") print(f" - Models: {total_models}") print(f" - Sparse configs: {total_configs}") print(f" - Benchmark-subsets: {total_benchmarks}") - print(f" - Estimated time: {total_combinations * TIMEOUT_PER_BENCHMARK / 3600:.1f} hours (worst case)") - + print( + f" - Estimated time: {total_combinations * TIMEOUT_PER_BENCHMARK / 3600:.1f} hours (worst case)" + ) + # Create executor print(f"\n๐Ÿ”ง Initializing BenchmarkExecutor...") executor = BenchmarkExecutor( @@ -241,9 +271,9 @@ enable_resumability=ENABLE_RESUMABILITY, required_result_files=["raw_results.csv"], timeout_per_benchmark=TIMEOUT_PER_BENCHMARK, - verbose=True + verbose=True, ) - + # Run benchmarks print(f"\n๐ŸŽฏ Running Benchmark Matrix...") try: @@ -253,9 +283,9 @@ benchmark_configs=BENCHMARKS, adapter_config=ADAPTER_CONFIG, generation_kwargs=GENERATION_KWARGS, - request_kwargs=REQUEST_KWARGS + request_kwargs=REQUEST_KWARGS, ) - + # Print summary print(f"\nโœ… Benchmark Execution Completed!") print(f" - Total: {results.progress.total_stubs}") @@ -263,10 +293,10 @@ print(f" - Failed: {results.progress.failed_stubs}") print(f" - Skipped: {results.progress.skipped_stubs}") print(f" - Results saved to: {RESULT_DIR}") - + except KeyboardInterrupt: print(f"\nโš ๏ธ Interrupted by user") print(f" Partial results in: {RESULT_DIR}") except Exception as e: print(f"\nโŒ Execution failed: {e}") - raise + raise diff --git a/benchmark/scripts/full_benchmarking/full_benchmark.py b/benchmark/scripts/full_benchmarking/full_benchmark.py index d37d4b7b..1fe318bf 100644 --- a/benchmark/scripts/full_benchmarking/full_benchmark.py +++ b/benchmark/scripts/full_benchmarking/full_benchmark.py @@ -42,7 +42,9 @@ from sparse_attention_hub.adapters.model_servers.huggingface import ModelServerHF ## spin a model server ### -model_server = ModelServerHF(ModelServerConfig(enable_stats_logging=True, delete_on_zero_reference=False)) +model_server = ModelServerHF( + ModelServerConfig(enable_stats_logging=True, delete_on_zero_reference=False) +) # ============================================================================ # CONFIGURATION @@ -503,7 +505,7 @@ def get_random_sampling_config_name(sink_size, window_size, sampling_rate): ), ] -#SPARSE_CONFIGS = [("dense", None)] +# SPARSE_CONFIGS = [("dense", None)] # ========================================================================== # Benchmark List @@ -578,7 +580,7 @@ def get_random_sampling_config_name(sink_size, window_size, sampling_rate): # mock_benchmark_config, # niah1, niah2, niah3, cwe, fwe, vt, qa1, qa2, multikey1, multikey2, multikey3, multikey, multivalue cwe, - niah1 + niah1, ] diff --git a/benchmark/scripts/full_benchmarking/generate_results_table.py b/benchmark/scripts/full_benchmarking/generate_results_table.py index 701ace74..8f4fbc51 100755 --- a/benchmark/scripts/full_benchmarking/generate_results_table.py +++ b/benchmark/scripts/full_benchmarking/generate_results_table.py @@ -22,40 +22,40 @@ def find_dataset_files(base_folder: str, dataset_name: str) -> List[Path]: """ Find all files corresponding to the given dataset in the base folder. - + Args: base_folder: Path to the base folder containing benchmark results dataset_name: Name of the dataset to search for - + Returns: List of paths to dataset directories """ base_path = Path(base_folder) dataset_paths = [] - + # Walk through the directory structure for model_dir in base_path.iterdir(): if not model_dir.is_dir(): continue - + for config_dir in model_dir.iterdir(): if not config_dir.is_dir(): continue - + dataset_dir = config_dir / dataset_name if dataset_dir.exists(): dataset_paths.append(dataset_dir) - + return dataset_paths def extract_config_name(dataset_path: Path) -> str: """ Extract the configuration name from the dataset path. - + Args: dataset_path: Path to the dataset directory - + Returns: Configuration name """ @@ -66,49 +66,51 @@ def extract_config_name(dataset_path: Path) -> str: def parse_metrics_json(metrics_file: Path) -> Dict[str, Any]: """ Parse the metrics.json file to extract macro metrics. - + Args: metrics_file: Path to the metrics.json file - + Returns: Dictionary containing the parsed metrics """ try: - with open(metrics_file, 'r') as f: + with open(metrics_file, "r") as f: data = json.load(f) - + metrics = {} - + # Extract overall score - if 'overall_score' in data: - metrics['overall_score'] = data['overall_score'] - + if "overall_score" in data: + metrics["overall_score"] = data["overall_score"] + # Extract task-specific scores - if 'task_scores' in data: - for task_name, task_metrics in data['task_scores'].items(): + if "task_scores" in data: + for task_name, task_metrics in data["task_scores"].items(): for metric_name, metric_value in task_metrics.items(): # Create a unique metric name if there are multiple tasks - if len(data['task_scores']) > 1: + if len(data["task_scores"]) > 1: metric_key = f"{task_name}_{metric_name}" else: metric_key = metric_name metrics[metric_key] = metric_value - + return metrics - + except Exception as e: print(f"Warning: Could not parse {metrics_file}: {e}") return {} -def parse_micro_metrics_jsonl(micro_metrics_file: Path, max_lines: int = 1000) -> Dict[str, float]: +def parse_micro_metrics_jsonl( + micro_metrics_file: Path, max_lines: int = 1000 +) -> Dict[str, float]: """ Parse the micro_metrics.jsonl file to extract average density and attention error. - + Args: micro_metrics_file: Path to the micro_metrics.jsonl file max_lines: Maximum number of lines to read - + Returns: Dictionary containing average density and attention error """ @@ -116,37 +118,37 @@ def parse_micro_metrics_jsonl(micro_metrics_file: Path, max_lines: int = 1000) - density_values = [] error_values = [] line_count = 0 - - with open(micro_metrics_file, 'r') as f: + + with open(micro_metrics_file, "r") as f: for line in f: if line_count >= max_lines: break - + try: data = json.loads(line.strip()) - metric_name = data.get('metric', '') - value = data.get('value', 0.0) - - if metric_name == 'research_attention_density': + metric_name = data.get("metric", "") + value = data.get("value", 0.0) + + if metric_name == "research_attention_density": density_values.append(value) - elif metric_name == 'research_attention_output_error': + elif metric_name == "research_attention_output_error": error_values.append(value) - + except json.JSONDecodeError: continue - + line_count += 1 - + micro_metrics = {} - + if density_values: - micro_metrics['avg_density'] = sum(density_values) / len(density_values) - + micro_metrics["avg_density"] = sum(density_values) / len(density_values) + if error_values: - micro_metrics['avg_attention_error'] = sum(error_values) / len(error_values) - + micro_metrics["avg_attention_error"] = sum(error_values) / len(error_values) + return micro_metrics - + except Exception as e: print(f"Warning: Could not parse {micro_metrics_file}: {e}") return {} @@ -155,97 +157,97 @@ def parse_micro_metrics_jsonl(micro_metrics_file: Path, max_lines: int = 1000) - def get_all_available_metrics(dataset_paths: List[Path]) -> List[str]: """ Get all available metrics across all dataset paths. - + Args: dataset_paths: List of paths to dataset directories - + Returns: List of all available metric names """ all_metrics = set() - + for dataset_path in dataset_paths: metrics_file = dataset_path / "metrics.json" if metrics_file.exists(): metrics = parse_metrics_json(metrics_file) all_metrics.update(metrics.keys()) - + micro_metrics_file = dataset_path / "micro_metrics.jsonl" if micro_metrics_file.exists(): micro_metrics = parse_micro_metrics_jsonl(micro_metrics_file) all_metrics.update(micro_metrics.keys()) - + return sorted(list(all_metrics)) def generate_results_table(dataset_name: str, base_folder: str) -> pd.DataFrame: """ Generate a results table from benchmark data. - + Args: dataset_name: Name of the dataset to analyze base_folder: Path to the base folder containing benchmark results - + Returns: DataFrame with configs as rows and metrics as columns """ print(f"๐Ÿ” Finding dataset files for '{dataset_name}' in '{base_folder}'...") dataset_paths = find_dataset_files(base_folder, dataset_name) - + if not dataset_paths: print(f"โŒ No dataset files found for '{dataset_name}' in '{base_folder}'") return pd.DataFrame() - + print(f"โœ… Found {len(dataset_paths)} dataset directories") - + # Get all available metrics print("๐Ÿ“Š Discovering available metrics...") all_metrics = get_all_available_metrics(dataset_paths) print(f"โœ… Found {len(all_metrics)} metrics: {', '.join(all_metrics)}") - + # Initialize results dictionary results = [] - + print("๐Ÿ“ˆ Processing each configuration...") for dataset_path in dataset_paths: config_name = extract_config_name(dataset_path) print(f" Processing: {config_name}") - - row_data = {'config': config_name} - + + row_data = {"config": config_name} + # Parse macro metrics metrics_file = dataset_path / "metrics.json" if metrics_file.exists(): macro_metrics = parse_metrics_json(metrics_file) row_data.update(macro_metrics) - + # Parse micro metrics micro_metrics_file = dataset_path / "micro_metrics.jsonl" if micro_metrics_file.exists(): micro_metrics = parse_micro_metrics_jsonl(micro_metrics_file) row_data.update(micro_metrics) - + results.append(row_data) - + # Create DataFrame df = pd.DataFrame(results) - + if df.empty: print("โŒ No results found") return df - + # Reorder columns to put config first, then metrics - if 'config' in df.columns: - other_cols = [col for col in df.columns if col != 'config'] - df = df[['config'] + other_cols] - + if "config" in df.columns: + other_cols = [col for col in df.columns if col != "config"] + df = df[["config"] + other_cols] + return df def save_results_table(df: pd.DataFrame, dataset_name: str, base_folder: str) -> None: """ Save the results table to files. - + Args: df: DataFrame containing the results dataset_name: Name of the dataset @@ -254,21 +256,21 @@ def save_results_table(df: pd.DataFrame, dataset_name: str, base_folder: str) -> if df.empty: print("โŒ No data to save") return - + # Create output directory output_dir = Path(base_folder) / "results_tables" output_dir.mkdir(exist_ok=True) - + # Save as CSV csv_file = output_dir / f"{dataset_name}_results.csv" df.to_csv(csv_file, index=False) print(f"๐Ÿ’พ Saved CSV results to: {csv_file}") - + # Save as Excel excel_file = output_dir / f"{dataset_name}_results.xlsx" df.to_excel(excel_file, index=False) print(f"๐Ÿ’พ Saved Excel results to: {excel_file}") - + # Print summary print(f"\n๐Ÿ“Š Results Summary:") print(f" - Configurations: {len(df)}") @@ -285,43 +287,42 @@ def main(): Examples: python generate_results_table.py loogle_shortdep_cloze full_benchmark.matrix python generate_results_table.py longbench_passage_retrieval_en ./results/ - """ + """, ) - + parser.add_argument( "dataset_name", - help="Name of the dataset to analyze (e.g., loogle_shortdep_cloze)" + help="Name of the dataset to analyze (e.g., loogle_shortdep_cloze)", ) - + parser.add_argument( - "base_folder", - help="Path to the base folder containing benchmark results" + "base_folder", help="Path to the base folder containing benchmark results" ) - + args = parser.parse_args() - + print("๐Ÿš€ Starting Results Table Generation") print("=" * 50) print(f"Dataset: {args.dataset_name}") print(f"Base folder: {args.base_folder}") print() - + # Generate the results table df = generate_results_table(args.dataset_name, args.base_folder) - + if not df.empty: # Display the table print("\n๐Ÿ“‹ Results Table:") print("=" * 80) print(df.to_string(index=False)) - + # Save the results save_results_table(df, args.dataset_name, args.base_folder) - + print(f"\nโœ… Results table generation completed successfully!") else: print(f"\nโŒ No results found for dataset '{args.dataset_name}'") if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/benchmark/scripts/micro_benchmarking/analyse_stress_tests.py b/benchmark/scripts/micro_benchmarking/analyse_stress_tests.py index ba3e3444..8529d271 100644 --- a/benchmark/scripts/micro_benchmarking/analyse_stress_tests.py +++ b/benchmark/scripts/micro_benchmarking/analyse_stress_tests.py @@ -20,7 +20,7 @@ def parse_config_name(config_name: str) -> Dict[str, float]: """Parse configuration name to extract parameters. - + Args: config_name: Configuration name like "adaptive_sampling.sink_0.001_window_0.001_heavy_0.005_base_0.01_epsilon_0.01_delta_0.01" or "oracle_top_k_0.5.sink_0.02_window_0.02" @@ -28,16 +28,16 @@ def parse_config_name(config_name: str) -> Dict[str, float]: or "hashattention.sink_0.001_window_0.001_top_k_0.17" or "adaptive_sampling_hat.sink_0.01_window_0.01_heavy_0.02_base_0.01_epsilon_0.5_delta_0.5" or "random_sampling.sink_0.001_window_0.001_sampling_rate_0.01" - + Returns: Dictionary with parsed parameters """ # Extract parameters using regex for different configuration types - + # Pattern for adaptive_sampling_hat (must come before adaptive_sampling to avoid conflicts) adaptive_hat_pattern = r"adaptive_sampling_hat\.sink_([\d.]+)_window_([\d.]+)_heavy_([\d.]+)_base_([\d.]+)_epsilon_([\d.]+)_delta_([\d.]+)" adaptive_hat_match = re.match(adaptive_hat_pattern, config_name) - + if adaptive_hat_match: return { "config_type": "adaptive_sampling_hat", @@ -46,13 +46,13 @@ def parse_config_name(config_name: str) -> Dict[str, float]: "heavy_size": float(adaptive_hat_match.group(3)), "base_rate_sampling": float(adaptive_hat_match.group(4)), "epsilon": float(adaptive_hat_match.group(5)), - "delta": float(adaptive_hat_match.group(6)) + "delta": float(adaptive_hat_match.group(6)), } - + # Pattern for adaptive_sampling adaptive_pattern = r"adaptive_sampling\.sink_([\d.]+)_window_([\d.]+)_heavy_([\d.]+)_base_([\d.]+)_epsilon_([\d.]+)_delta_([\d.]+)" adaptive_match = re.match(adaptive_pattern, config_name) - + if adaptive_match: return { "config_type": "adaptive_sampling", @@ -61,97 +61,103 @@ def parse_config_name(config_name: str) -> Dict[str, float]: "heavy_size": float(adaptive_match.group(3)), "base_rate_sampling": float(adaptive_match.group(4)), "epsilon": float(adaptive_match.group(5)), - "delta": float(adaptive_match.group(6)) + "delta": float(adaptive_match.group(6)), } - + # Pattern for oracle_top_k top_k_pattern = r"oracle_top_k_([\d.]+)\.sink_([\d.]+)_window_([\d.]+)" top_k_match = re.match(top_k_pattern, config_name) - + if top_k_match: return { "config_type": "oracle_top_k", "top_k": float(top_k_match.group(1)), "sink_size": float(top_k_match.group(2)), - "window_size": float(top_k_match.group(3)) + "window_size": float(top_k_match.group(3)), } - + # Pattern for oracle_top_p top_p_pattern = r"oracle_top_p_([\d.]+)\.sink_([\d.]+)_window_([\d.]+)" top_p_match = re.match(top_p_pattern, config_name) - + if top_p_match: return { "config_type": "oracle_top_p", "top_p": float(top_p_match.group(1)), "sink_size": float(top_p_match.group(2)), - "window_size": float(top_p_match.group(3)) + "window_size": float(top_p_match.group(3)), } - + # Pattern for hashattention - hashattention_pattern = r"hashattention\.sink_([\d.]+)_window_([\d.]+)_top_k_([\d.]+)" + hashattention_pattern = ( + r"hashattention\.sink_([\d.]+)_window_([\d.]+)_top_k_([\d.]+)" + ) hashattention_match = re.match(hashattention_pattern, config_name) - + if hashattention_match: return { "config_type": "hashattention", "sink_size": float(hashattention_match.group(1)), "window_size": float(hashattention_match.group(2)), - "hat_top_k": float(hashattention_match.group(3)) + "hat_top_k": float(hashattention_match.group(3)), } - + # Pattern for random_sampling - random_sampling_pattern = r"random_sampling\.sink_([\d.]+)_window_([\d.]+)_sampling_rate_([\d.]+)" + random_sampling_pattern = ( + r"random_sampling\.sink_([\d.]+)_window_([\d.]+)_sampling_rate_([\d.]+)" + ) random_sampling_match = re.match(random_sampling_pattern, config_name) - + if random_sampling_match: return { "config_type": "random_sampling", "sink_size": float(random_sampling_match.group(1)), "window_size": float(random_sampling_match.group(2)), - "sampling_rate": float(random_sampling_match.group(3)) + "sampling_rate": float(random_sampling_match.group(3)), } - + # If no pattern matches, return empty dict return {"config_type": "unknown"} def load_config_file(config_path: Path) -> Dict[str, Any]: """Load configuration from JSON file. - + Args: config_path: Path to config.json file - + Returns: Configuration dictionary """ - with open(config_path, 'r') as f: + with open(config_path, "r") as f: return json.load(f) def load_micro_metrics(metrics_path: Path) -> List[Dict[str, Any]]: """Load micro metrics from JSONL file. - + Args: metrics_path: Path to micro_metrics.jsonl file - + Returns: List of metric entries """ metrics = [] - with open(metrics_path, 'r') as f: + with open(metrics_path, "r") as f: for line in f: if line.strip(): metrics.append(json.loads(line)) return metrics -def process_experiment_directory(exp_dir: Path) -> List[Tuple[List[Dict[str, Any]], Dict[str, Any], str]]: +def process_experiment_directory( + exp_dir: Path, +) -> List[Tuple[List[Dict[str, Any]], Dict[str, Any], str]]: """Process a single experiment directory. - + Args: exp_dir: Path to experiment directory - + Returns: List of tuples (metrics_data, config_data, dataset_name) for each benchmark directory """ @@ -159,45 +165,45 @@ def process_experiment_directory(exp_dir: Path) -> List[Tuple[List[Dict[str, Any benchmark_dirs = [d for d in exp_dir.iterdir() if d.is_dir()] if not benchmark_dirs: return [] - + results = [] - + for benchmark_dir in benchmark_dirs: dataset_name = benchmark_dir.name - + # Load configuration config_path = benchmark_dir / "config.json" if not config_path.exists(): continue - + config = load_config_file(config_path) - + # Load micro metrics metrics_path = benchmark_dir / "micro_metrics.jsonl" if not metrics_path.exists(): continue - + metrics = load_micro_metrics(metrics_path) - + results.append((metrics, config, dataset_name)) - + return results def extract_sparse_config_params(config: Dict[str, Any]) -> Dict[str, Any]: """Extract sparse attention configuration parameters. - + Args: config: Configuration dictionary - + Returns: Dictionary with sparse attention parameters """ sparse_config = config.get("sparse_attention_config", {}) masker_configs = sparse_config.get("masker_configs", []) - + params = {} - + # Extract parameters from masker configs for masker_config in masker_configs: if "sink_size" in masker_config: @@ -226,55 +232,61 @@ def extract_sparse_config_params(config: Dict[str, Any]) -> Dict[str, Any]: elif "sampling_rate" in masker_config: # Random sampling parameters params["sampling_rate"] = masker_config["sampling_rate"] - + return params -def organize_metrics_by_layer(metrics: List[Dict[str, Any]]) -> Dict[int, Dict[str, float]]: +def organize_metrics_by_layer( + metrics: List[Dict[str, Any]] +) -> Dict[int, Dict[str, float]]: """Organize metrics by layer index and average multiple measurements. - + Args: metrics: List of metric entries - + Returns: Dictionary mapping layer_idx to averaged metrics """ layer_metrics = {} - + # First pass: collect all values for each layer for metric in metrics: layer_idx = metric.get("metadata", {}).get("layer_idx") if layer_idx is None: continue - + if layer_idx not in layer_metrics: layer_metrics[layer_idx] = {"density": [], "error": []} - + metric_name = metric.get("metric") value = metric.get("value") - + if metric_name == "research_attention_density": layer_metrics[layer_idx]["density"].append(value) elif metric_name == "research_attention_output_error": layer_metrics[layer_idx]["error"].append(value) - + # Second pass: average the collected values averaged_metrics = {} for layer_idx, values in layer_metrics.items(): averaged_metrics[layer_idx] = {} - + if values["density"]: - averaged_metrics[layer_idx]["density"] = sum(values["density"]) / len(values["density"]) - + averaged_metrics[layer_idx]["density"] = sum(values["density"]) / len( + values["density"] + ) + if values["error"]: - averaged_metrics[layer_idx]["error"] = sum(values["error"]) / len(values["error"]) - + averaged_metrics[layer_idx]["error"] = sum(values["error"]) / len( + values["error"] + ) + return averaged_metrics def analyze_stress_tests(results_dir: str, output_dir: str) -> None: """Analyze stress test results and generate TSV files. - + Args: results_dir: Path to stress_test_adaptive.matrix directory output_dir: Output directory for TSV files @@ -282,39 +294,39 @@ def analyze_stress_tests(results_dir: str, output_dir: str) -> None: results_path = Path(results_dir) output_path = Path(output_dir) output_path.mkdir(exist_ok=True) - + # Find model directories model_dirs = [d for d in results_path.iterdir() if d.is_dir()] - + all_vector_data = [] all_metadata = [] - + for model_dir in model_dirs: model_name = model_dir.name - + # Find configuration directories config_dirs = [d for d in model_dir.iterdir() if d.is_dir()] - + for config_dir in config_dirs: config_name = config_dir.name - + # Parse configuration name parsed_params = parse_config_name(config_name) - + # Process experiment directory (now returns list of results for each benchmark) benchmark_results = process_experiment_directory(config_dir) - + if not benchmark_results: continue - + # Process each benchmark result for metrics, config, dataset_name in benchmark_results: # Extract sparse attention parameters sparse_params = extract_sparse_config_params(config) - + # Organize metrics by layer layer_metrics = organize_metrics_by_layer(metrics) - + # Generate vector data for layer_idx, layer_data in layer_metrics.items(): if "density" in layer_data and "error" in layer_data: @@ -323,10 +335,10 @@ def analyze_stress_tests(results_dir: str, output_dir: str) -> None: "config": config_name, "layer_idx": layer_idx, "density": layer_data["density"], - "error": layer_data["error"] + "error": layer_data["error"], } all_vector_data.append(vector_entry) - + # Generate metadata entry metadata_entry = { "model": model_name, @@ -334,46 +346,44 @@ def analyze_stress_tests(results_dir: str, output_dir: str) -> None: "dataset": dataset_name, "layer_idx": "all", # This will be expanded for each layer **parsed_params, - **sparse_params + **sparse_params, } - + # Add metadata for each layer for layer_idx in layer_metrics.keys(): layer_metadata = metadata_entry.copy() layer_metadata["layer_idx"] = layer_idx all_metadata.append(layer_metadata) - + # Write vector.tsv vector_path = output_path / "vector.tsv" metadata_path = output_path / "metadata.tsv" - + # Write vector data - with open(vector_path, 'w') as f: + with open(vector_path, "w") as f: f.write("density\terror\n") for entry in all_vector_data: f.write(f"{entry['density']}\t{entry['error']}\n") - + # Write metadata - with open(metadata_path, 'w') as f: + with open(metadata_path, "w") as f: if all_metadata: # Get all unique keys from all metadata entries all_keys = set() for entry in all_metadata: all_keys.update(entry.keys()) - + # Sort keys for consistent output sorted_keys = sorted(all_keys) - + # Write header f.write("\t".join(sorted_keys) + "\n") - + # Write data for entry in all_metadata: row = [str(entry.get(key, "")) for key in sorted_keys] f.write("\t".join(row) + "\n") - - print(f"Analysis complete!") print(f"Vector data written to: {vector_path}") print(f"Metadata written to: {metadata_path}") @@ -385,25 +395,25 @@ def main(): """Main function.""" parser = argparse.ArgumentParser(description="Analyze stress test results") parser.add_argument( - "--results-dir", + "--results-dir", default="./stress_test_adaptive.matrix", - help="Path to stress test results directory" + help="Path to stress test results directory", ) parser.add_argument( - "--output-dir", + "--output-dir", default="./sparse-attention-hub-share/docs/micro_tests/", - help="Output directory for TSV files" + help="Output directory for TSV files", ) - + args = parser.parse_args() - + # Check if results directory exists if not os.path.exists(args.results_dir): print(f"Error: Results directory '{args.results_dir}' does not exist") return - + analyze_stress_tests(args.results_dir, args.output_dir) if __name__ == "__main__": - main() + main() diff --git a/benchmark/scripts/micro_benchmarking/plot_stress_test_results.py b/benchmark/scripts/micro_benchmarking/plot_stress_test_results.py index 001bcc8e..1fa50339 100644 --- a/benchmark/scripts/micro_benchmarking/plot_stress_test_results.py +++ b/benchmark/scripts/micro_benchmarking/plot_stress_test_results.py @@ -20,29 +20,31 @@ def load_tsv_data(vector_path: str, metadata_path: str) -> pd.DataFrame: """Load and merge vector and metadata TSV files. - + Args: vector_path: Path to vector.tsv file metadata_path: Path to metadata.tsv file - + Returns: Merged DataFrame with all data """ # Load the data - vector_df = pd.read_csv(vector_path, sep='\t') - metadata_df = pd.read_csv(metadata_path, sep='\t') - + vector_df = pd.read_csv(vector_path, sep="\t") + metadata_df = pd.read_csv(metadata_path, sep="\t") + # Merge the dataframes # Since both files have the same number of rows in the same order, # we can simply concatenate them merged_df = pd.concat([vector_df, metadata_df], axis=1) - + return merged_df -def create_interactive_scatter_plot(df: pd.DataFrame, output_path: str, dataset_name: str = "") -> None: +def create_interactive_scatter_plot( + df: pd.DataFrame, output_path: str, dataset_name: str = "" +) -> None: """Create an interactive scatter plot of error vs density. - + Args: df: DataFrame containing the data output_path: Path to save the HTML plot @@ -50,21 +52,28 @@ def create_interactive_scatter_plot(df: pd.DataFrame, output_path: str, dataset_ """ # Create the scatter plot fig = go.Figure() - + # Define colors for different configuration types config_colors = { - 'adaptive_sampling': '#1f77b4', # Blue - 'oracle_top_k': '#ff7f0e', # Orange - 'oracle_top_p': '#2ca02c', # Green - 'hashattention': '#d62728', # Red - 'adaptive_sampling_hat': '#9467bd', # Purple - 'random_sampling': '#8c564b' # Brown + "adaptive_sampling": "#1f77b4", # Blue + "oracle_top_k": "#ff7f0e", # Orange + "oracle_top_p": "#2ca02c", # Green + "hashattention": "#d62728", # Red + "adaptive_sampling_hat": "#9467bd", # Purple + "random_sampling": "#8c564b", # Brown } - + # Add scatter traces for each configuration type - for config_type in ['adaptive_sampling', 'oracle_top_k', 'oracle_top_p', 'hashattention', 'adaptive_sampling_hat', 'random_sampling']: - config_data = df[df['config_type'] == config_type] - + for config_type in [ + "adaptive_sampling", + "oracle_top_k", + "oracle_top_p", + "hashattention", + "adaptive_sampling_hat", + "random_sampling", + ]: + config_data = df[df["config_type"] == config_type] + if len(config_data) > 0: # Create hover text for this configuration type hover_text = [] @@ -77,20 +86,20 @@ def create_interactive_scatter_plot(df: pd.DataFrame, output_path: str, dataset_ Sink Size: {row.get('sink_size', 'N/A')}
Window Size: {row.get('window_size', 'N/A')}
""" - + # Add configuration-specific parameters - if config_type == 'adaptive_sampling': + if config_type == "adaptive_sampling": config_info += f""" Heavy Size: {row.get('heavy_size', 'N/A')}
Base Rate: {row.get('base_rate_sampling', 'N/A')}
Epsilon: {row.get('epsilon', 'N/A')}
Delta: {row.get('delta', 'N/A')}
""" - elif config_type == 'oracle_top_k': + elif config_type == "oracle_top_k": config_info += f"Top-K: {row.get('top_k', 'N/A')}
" - elif config_type == 'oracle_top_p': + elif config_type == "oracle_top_p": config_info += f"Top-P: {row.get('top_p', 'N/A')}
" - elif config_type == 'hashattention': + elif config_type == "hashattention": config_info += f""" Hash Top-K: {row.get('hat_top_k', 'N/A')}
Hash Heavy Size: {row.get('hat_heavy_size', 'N/A')}
@@ -99,7 +108,7 @@ def create_interactive_scatter_plot(df: pd.DataFrame, output_path: str, dataset_ Hash MLP Hidden Size: {row.get('hat_mlp_hidden_size', 'N/A')}
Hash MLP Activation: {row.get('hat_mlp_activation', 'N/A')}
""" - elif config_type == 'adaptive_sampling_hat': + elif config_type == "adaptive_sampling_hat": config_info += f""" Heavy Size: {row.get('heavy_size', 'N/A')}
Base Rate: {row.get('base_rate_sampling', 'N/A')}
@@ -111,74 +120,69 @@ def create_interactive_scatter_plot(df: pd.DataFrame, output_path: str, dataset_ Hash MLP Hidden Size: {row.get('hat_mlp_hidden_size', 'N/A')}
Hash MLP Activation: {row.get('hat_mlp_activation', 'N/A')}
""" - elif config_type == 'random_sampling': - config_info += f"Sampling Rate: {row.get('sampling_rate', 'N/A')}
" - + elif config_type == "random_sampling": + config_info += ( + f"Sampling Rate: {row.get('sampling_rate', 'N/A')}
" + ) + config_info += f""" Density: {row.get('density', 'N/A'):.4f}
Error: {row.get('error', 'N/A'):.4f} """ hover_text.append(config_info) - + fig.add_trace( go.Scatter( - x=config_data['density'], - y=config_data['error'], - mode='markers', - marker=dict( - size=6, - color=config_colors[config_type], - opacity=0.7 - ), + x=config_data["density"], + y=config_data["error"], + mode="markers", + marker=dict(size=6, color=config_colors[config_type], opacity=0.7), text=hover_text, - hoverinfo='text', - hovertemplate='%{text}', - name=config_type.replace('_', ' ').title() + hoverinfo="text", + hovertemplate="%{text}", + name=config_type.replace("_", " ").title(), ) ) - + # Create title with dataset name if provided - title_text = 'Sparse Attention: Error vs Density (All Configurations)' + title_text = "Sparse Attention: Error vs Density (All Configurations)" if dataset_name: - title_text = f'Sparse Attention: Error vs Density - {dataset_name}' - + title_text = f"Sparse Attention: Error vs Density - {dataset_name}" + # Update layout fig.update_layout( - title={ - 'text': title_text, - 'x': 0.5, - 'xanchor': 'center', - 'font': {'size': 20} - }, - xaxis_title='Density', - yaxis_title='Error', + title={"text": title_text, "x": 0.5, "xanchor": "center", "font": {"size": 20}}, + xaxis_title="Density", + yaxis_title="Error", xaxis=dict( title_font=dict(size=16), tickfont=dict(size=12), - gridcolor='lightgray', - zeroline=False + gridcolor="lightgray", + zeroline=False, ), yaxis=dict( title_font=dict(size=16), tickfont=dict(size=12), - gridcolor='lightgray', - zeroline=False + gridcolor="lightgray", + zeroline=False, ), - plot_bgcolor='white', - hovermode='closest', + plot_bgcolor="white", + hovermode="closest", width=1000, height=700, - showlegend=True + showlegend=True, ) - + # Save the plot fig.write_html(output_path) print(f"Interactive plot saved to: {output_path}") -def create_configuration_analysis_plots(df: pd.DataFrame, output_dir: str, dataset_name: str = "") -> None: +def create_configuration_analysis_plots( + df: pd.DataFrame, output_dir: str, dataset_name: str = "" +) -> None: """Create additional analysis plots for different configurations. - + Args: df: DataFrame containing the data output_dir: Directory to save the plots @@ -186,212 +190,264 @@ def create_configuration_analysis_plots(df: pd.DataFrame, output_dir: str, datas """ output_path = Path(output_dir) output_path.mkdir(exist_ok=True) - + # 1. Plot by configuration type with subplots - config_types = df['config_type'].unique() - + config_types = df["config_type"].unique() + fig = make_subplots( - rows=1, cols=len(config_types), + rows=1, + cols=len(config_types), subplot_titles=[f"{ct.replace('_', ' ').title()}" for ct in config_types], - specs=[[{"secondary_y": False}] * len(config_types)] + specs=[[{"secondary_y": False}] * len(config_types)], ) - - colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b'] # Blue, Orange, Green, Red, Purple, Brown - + + colors = [ + "#1f77b4", + "#ff7f0e", + "#2ca02c", + "#d62728", + "#9467bd", + "#8c564b", + ] # Blue, Orange, Green, Red, Purple, Brown + for i, config_type in enumerate(config_types): - config_data = df[df['config_type'] == config_type] - + config_data = df[df["config_type"] == config_type] + fig.add_trace( go.Scatter( - x=config_data['density'], - y=config_data['error'], - mode='markers', + x=config_data["density"], + y=config_data["error"], + mode="markers", marker=dict(size=8, color=colors[i], opacity=0.7), - name=config_type.replace('_', ' ').title(), - text=[f"Layer: {layer}
Density: {d:.4f}
Error: {e:.4f}" - for layer, d, e in zip(config_data['layer_idx'], config_data['density'], config_data['error'])], - hoverinfo='text', - showlegend=False + name=config_type.replace("_", " ").title(), + text=[ + f"Layer: {layer}
Density: {d:.4f}
Error: {e:.4f}" + for layer, d, e in zip( + config_data["layer_idx"], + config_data["density"], + config_data["error"], + ) + ], + hoverinfo="text", + showlegend=False, ), - row=1, col=i+1 + row=1, + col=i + 1, ) - + # Create title with dataset name if provided - title_text = 'Error vs Density by Configuration Type' + title_text = "Error vs Density by Configuration Type" if dataset_name: - title_text = f'Error vs Density by Configuration Type - {dataset_name}' - - fig.update_layout( - title=title_text, - showlegend=False, - width=1200, - height=500 - ) - + title_text = f"Error vs Density by Configuration Type - {dataset_name}" + + fig.update_layout(title=title_text, showlegend=False, width=1200, height=500) + fig.write_html(output_path / "config_type_analysis.html") - print(f"Configuration type analysis plot saved to: {output_path / 'config_type_analysis.html'}") - + print( + f"Configuration type analysis plot saved to: {output_path / 'config_type_analysis.html'}" + ) + # 2. Layer-wise analysis with configuration type colors - layer_groups = df.groupby('layer_idx') - + layer_groups = df.groupby("layer_idx") + fig2 = go.Figure() - + # Define colors for different configuration types config_colors = { - 'adaptive_sampling': '#1f77b4', # Blue - 'oracle_top_k': '#ff7f0e', # Orange - 'oracle_top_p': '#2ca02c', # Green - 'hashattention': '#d62728', # Red - 'adaptive_sampling_hat': '#9467bd', # Purple - 'random_sampling': '#8c564b' # Brown + "adaptive_sampling": "#1f77b4", # Blue + "oracle_top_k": "#ff7f0e", # Orange + "oracle_top_p": "#2ca02c", # Green + "hashattention": "#d62728", # Red + "adaptive_sampling_hat": "#9467bd", # Purple + "random_sampling": "#8c564b", # Brown } - + for layer_idx, group in layer_groups: # Color by configuration type - colors_for_layer = [config_colors.get(ct, '#000000') for ct in group['config_type']] - + colors_for_layer = [ + config_colors.get(ct, "#000000") for ct in group["config_type"] + ] + fig2.add_trace( go.Scatter( - x=group['density'], - y=group['error'], - mode='markers', + x=group["density"], + y=group["error"], + mode="markers", marker=dict(size=6, color=colors_for_layer, opacity=0.7), - name=f'Layer {layer_idx}', - text=[f"Config: {config}
Type: {ct}
Density: {d:.4f}
Error: {e:.4f}" - for config, ct, d, e in zip(group['config'], group['config_type'], group['density'], group['error'])], - hoverinfo='text' + name=f"Layer {layer_idx}", + text=[ + f"Config: {config}
Type: {ct}
Density: {d:.4f}
Error: {e:.4f}" + for config, ct, d, e in zip( + group["config"], + group["config_type"], + group["density"], + group["error"], + ) + ], + hoverinfo="text", ) ) - + # Create title with dataset name if provided - title_text2 = 'Error vs Density by Layer (Colored by Config Type)' + title_text2 = "Error vs Density by Layer (Colored by Config Type)" if dataset_name: - title_text2 = f'Error vs Density by Layer (Colored by Config Type) - {dataset_name}' - + title_text2 = ( + f"Error vs Density by Layer (Colored by Config Type) - {dataset_name}" + ) + fig2.update_layout( title=title_text2, - xaxis_title='Density', - yaxis_title='Error', + xaxis_title="Density", + yaxis_title="Error", width=1000, - height=700 + height=700, ) - + fig2.write_html(output_path / "layer_analysis.html") print(f"Layer analysis plot saved to: {output_path / 'layer_analysis.html'}") - + # 3. Configuration comparison plot fig3 = go.Figure() - - for config_type in ['adaptive_sampling', 'oracle_top_k', 'oracle_top_p', 'hashattention', 'adaptive_sampling_hat', 'random_sampling']: - config_data = df[df['config_type'] == config_type] - + + for config_type in [ + "adaptive_sampling", + "oracle_top_k", + "oracle_top_p", + "hashattention", + "adaptive_sampling_hat", + "random_sampling", + ]: + config_data = df[df["config_type"] == config_type] + if len(config_data) > 0: # Calculate average error and density for each configuration - config_avg = config_data.groupby('config').agg({ - 'error': 'mean', - 'density': 'mean' - }).reset_index() - + config_avg = ( + config_data.groupby("config") + .agg({"error": "mean", "density": "mean"}) + .reset_index() + ) + fig3.add_trace( go.Scatter( - x=config_avg['density'], - y=config_avg['error'], - mode='markers', - marker=dict( - size=10, - color=config_colors[config_type], - opacity=0.8 - ), - name=config_type.replace('_', ' ').title(), - text=[f"Config: {config}
Avg Density: {d:.4f}
Avg Error: {e:.4f}" - for config, d, e in zip(config_avg['config'], config_avg['density'], config_avg['error'])], - hoverinfo='text' + x=config_avg["density"], + y=config_avg["error"], + mode="markers", + marker=dict(size=10, color=config_colors[config_type], opacity=0.8), + name=config_type.replace("_", " ").title(), + text=[ + f"Config: {config}
Avg Density: {d:.4f}
Avg Error: {e:.4f}" + for config, d, e in zip( + config_avg["config"], + config_avg["density"], + config_avg["error"], + ) + ], + hoverinfo="text", ) ) - + # Create title with dataset name if provided - title_text3 = 'Average Error vs Density by Configuration' + title_text3 = "Average Error vs Density by Configuration" if dataset_name: - title_text3 = f'Average Error vs Density by Configuration - {dataset_name}' - + title_text3 = f"Average Error vs Density by Configuration - {dataset_name}" + fig3.update_layout( title=title_text3, - xaxis_title='Average Density', - yaxis_title='Average Error', + xaxis_title="Average Density", + yaxis_title="Average Error", width=1000, height=700, - showlegend=True + showlegend=True, ) - + fig3.write_html(output_path / "config_comparison.html") - print(f"Configuration comparison plot saved to: {output_path / 'config_comparison.html'}") + print( + f"Configuration comparison plot saved to: {output_path / 'config_comparison.html'}" + ) def main(): """Main function to create interactive plots per dataset.""" - parser = argparse.ArgumentParser(description='Create interactive plots for stress test results') - parser.add_argument('--vector-file', default='./sparse-attention-hub-share/docs/micro_tests/vector.tsv', - help='Path to vector.tsv file') - parser.add_argument('--metadata-file', default='./sparse-attention-hub-share/docs/micro_tests/metadata.tsv', - help='Path to metadata.tsv file') - parser.add_argument('--output-dir', default='./sparse-attention-hub-share/docs/micro_tests/plots/', - help='Output directory for plots') - + parser = argparse.ArgumentParser( + description="Create interactive plots for stress test results" + ) + parser.add_argument( + "--vector-file", + default="./sparse-attention-hub-share/docs/micro_tests/vector.tsv", + help="Path to vector.tsv file", + ) + parser.add_argument( + "--metadata-file", + default="./sparse-attention-hub-share/docs/micro_tests/metadata.tsv", + help="Path to metadata.tsv file", + ) + parser.add_argument( + "--output-dir", + default="./sparse-attention-hub-share/docs/micro_tests/plots/", + help="Output directory for plots", + ) + args = parser.parse_args() - + # Load data print("Loading data...") df = load_tsv_data(args.vector_file, args.metadata_file) print(f"Loaded {len(df)} data points") - + # Check if dataset column exists - if 'dataset' not in df.columns: - print("Warning: No 'dataset' column found in metadata. Creating plots for all data combined.") + if "dataset" not in df.columns: + print( + "Warning: No 'dataset' column found in metadata. Creating plots for all data combined." + ) # Create output directory output_path = Path(args.output_dir) output_path.mkdir(exist_ok=True) - + # Create main interactive scatter plot print("Creating main interactive scatter plot...") create_interactive_scatter_plot(df, output_path / "error_vs_density.html") - + # Create additional analysis plots print("Creating additional analysis plots...") create_configuration_analysis_plots(df, args.output_dir) - + print("All plots created successfully!") print(f"Main plot: {output_path / 'error_vs_density.html'}") print(f"Additional plots: {output_path / 'config_analysis.html'}") print(f"Layer analysis: {output_path / 'layer_analysis.html'}") return # Group data by dataset - datasets = df['dataset'].unique() + datasets = df["dataset"].unique() # Filter out NaN values datasets = [d for d in datasets if pd.notna(d)] print(f"Found {len(datasets)} datasets: {datasets}") - + # Create plots for each dataset for dataset_name in datasets: print(f"\nProcessing dataset: {dataset_name}") - + # Filter data for this dataset - dataset_df = df[df['dataset'] == dataset_name] + dataset_df = df[df["dataset"] == dataset_name] print(f" Found {len(dataset_df)} data points for this dataset") - + # Create dataset-specific output directory dataset_output_dir = Path(args.output_dir) / dataset_name dataset_output_dir.mkdir(parents=True, exist_ok=True) - + # Create main interactive scatter plot for this dataset print(f" Creating main interactive scatter plot...") - create_interactive_scatter_plot(dataset_df, dataset_output_dir / "error_vs_density.html", dataset_name) - + create_interactive_scatter_plot( + dataset_df, dataset_output_dir / "error_vs_density.html", dataset_name + ) + # Create additional analysis plots for this dataset print(f" Creating additional analysis plots...") - create_configuration_analysis_plots(dataset_df, str(dataset_output_dir), dataset_name) - + create_configuration_analysis_plots( + dataset_df, str(dataset_output_dir), dataset_name + ) + print(f" Plots for {dataset_name} saved to: {dataset_output_dir}") - + print(f"\nAll plots created successfully!") print(f"Plots organized by dataset in: {args.output_dir}/") for dataset_name in datasets: @@ -399,4 +455,4 @@ def main(): if __name__ == "__main__": - main() + main() diff --git a/benchmark/scripts/micro_benchmarking/stress_tests_adaptive_matrix.py b/benchmark/scripts/micro_benchmarking/stress_tests_adaptive_matrix.py index 88d919ed..235540e4 100644 --- a/benchmark/scripts/micro_benchmarking/stress_tests_adaptive_matrix.py +++ b/benchmark/scripts/micro_benchmarking/stress_tests_adaptive_matrix.py @@ -20,12 +20,20 @@ from benchmark.executor import BenchmarkExecutor from benchmark.executor_config import BenchmarkConfig, AdapterConfig -from sparse_attention_hub.sparse_attention.research_attention import ResearchAttentionConfig +from sparse_attention_hub.sparse_attention.research_attention import ( + ResearchAttentionConfig, +) from sparse_attention_hub.sparse_attention.research_attention.maskers.fixed.implementations import ( - LocalMaskerConfig, SinkMaskerConfig, OracleTopKConfig, OracleTopPMaskerConfig, HashAttentionTopKMaskerConfig + LocalMaskerConfig, + SinkMaskerConfig, + OracleTopKConfig, + OracleTopPMaskerConfig, + HashAttentionTopKMaskerConfig, ) from sparse_attention_hub.sparse_attention.research_attention.maskers.sampling.implementations import ( - AdaptiveSamplingMaskerConfig, RandomSamplingMaskerConfig, MagicPigConfig + AdaptiveSamplingMaskerConfig, + RandomSamplingMaskerConfig, + MagicPigConfig, ) # ============================================================================ @@ -40,185 +48,380 @@ # Model List MODELS = [ - "meta-llama/Llama-3.1-8B-Instruct", + "meta-llama/Llama-3.1-8B-Instruct", ] -def get_adaptive_config_name(sink_size, window_size, heavy_size, base_rate_sampling, epsilon, delta): + +def get_adaptive_config_name( + sink_size, window_size, heavy_size, base_rate_sampling, epsilon, delta +): return f"adaptive_sampling.sink_{sink_size}_window_{window_size}_heavy_{heavy_size}_base_{base_rate_sampling}_epsilon_{epsilon}_delta_{delta}" -def get_adaptive_hat_config_name(sink_size, window_size, heavy_size, base_rate_sampling, epsilon, delta): + +def get_adaptive_hat_config_name( + sink_size, window_size, heavy_size, base_rate_sampling, epsilon, delta +): return f"adaptive_sampling_hat.sink_{sink_size}_window_{window_size}_heavy_{heavy_size}_base_{base_rate_sampling}_epsilon_{epsilon}_delta_{delta}" + def get_oracle_top_p_config_name(sink_size, window_size, top_p): return f"oracle_top_p_{top_p}.sink_{sink_size}_window_{window_size}" + def get_oracle_top_k_config_name(sink_size, window_size, top_k): return f"oracle_top_k_{top_k}.sink_{sink_size}_window_{window_size}" + def get_hashattention_config_name(sink_size, window_size, top_k): return f"hashattention.sink_{sink_size}_window_{window_size}_top_k_{top_k}" + def get_random_sampling_config_name(sink_size, window_size, sampling_rate): return f"random_sampling.sink_{sink_size}_window_{window_size}_sampling_rate_{sampling_rate}" + # Sparse Attention Configurations SPARSE_CONFIGS = [] # adaptive sampling + oracle top k + sink + window -for (epsilon, delta) in [(0.01, 0.01), (0.05, 0.05), (0.1, 0.1), (0.25, 0.25), (0.3, 0.3), (0.4, 0.4), (0.5, 0.5)]: - for (sink_size, window_size) in [(0.001, 0.001), (0.005, 0.005), (0.01, 0.01), (0.02, 0.02)]: +for epsilon, delta in [ + (0.01, 0.01), + (0.05, 0.05), + (0.1, 0.1), + (0.25, 0.25), + (0.3, 0.3), + (0.4, 0.4), + (0.5, 0.5), +]: + for sink_size, window_size in [ + (0.001, 0.001), + (0.005, 0.005), + (0.01, 0.01), + (0.02, 0.02), + ]: for heavy_size in [0.005, 0.01, 0.02, 0.05]: for base_rate_sampling in [0.01, 0.05, 0.1]: - SPARSE_CONFIGS.append((get_adaptive_config_name(sink_size, window_size, heavy_size, base_rate_sampling, epsilon, delta), ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=sink_size), - LocalMaskerConfig(window_size=window_size), - OracleTopKConfig(heavy_size=heavy_size), - AdaptiveSamplingMaskerConfig(base_rate_sampling=base_rate_sampling, epsilon=epsilon, delta=delta, init_offset=sink_size, local_offset=window_size) - ]))) + SPARSE_CONFIGS.append( + ( + get_adaptive_config_name( + sink_size, + window_size, + heavy_size, + base_rate_sampling, + epsilon, + delta, + ), + ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=sink_size), + LocalMaskerConfig(window_size=window_size), + OracleTopKConfig(heavy_size=heavy_size), + AdaptiveSamplingMaskerConfig( + base_rate_sampling=base_rate_sampling, + epsilon=epsilon, + delta=delta, + init_offset=sink_size, + local_offset=window_size, + ), + ] + ), + ) + ) # oracle top p + sink + window -for (sink_size, window_size) in [(0.001, 0.001), (0.005, 0.005), (0.01, 0.01), (0.02, 0.02)]: +for sink_size, window_size in [ + (0.001, 0.001), + (0.005, 0.005), + (0.01, 0.01), + (0.02, 0.02), +]: for top_p in [0.5, 0.75, 0.9, 0.95, 0.99]: - SPARSE_CONFIGS.append((get_oracle_top_p_config_name(sink_size, window_size, top_p), ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=sink_size), - LocalMaskerConfig(window_size=window_size), - OracleTopPMaskerConfig(top_p=top_p) - ]))) + SPARSE_CONFIGS.append( + ( + get_oracle_top_p_config_name(sink_size, window_size, top_p), + ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=sink_size), + LocalMaskerConfig(window_size=window_size), + OracleTopPMaskerConfig(top_p=top_p), + ] + ), + ) + ) # oracle top p + sink + window -for (sink_size, window_size) in [(0.001, 0.001), (0.005, 0.005), (0.01, 0.01), (0.02, 0.02)]: - for top_k in [0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]: - SPARSE_CONFIGS.append((get_oracle_top_k_config_name(sink_size, window_size, top_k), ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=sink_size), - LocalMaskerConfig(window_size=window_size), - OracleTopKConfig(heavy_size=top_k) - ]))) +for sink_size, window_size in [ + (0.001, 0.001), + (0.005, 0.005), + (0.01, 0.01), + (0.02, 0.02), +]: + for top_k in [ + 0.01, + 0.02, + 0.03, + 0.04, + 0.05, + 0.06, + 0.07, + 0.08, + 0.09, + 0.1, + 0.11, + 0.12, + 0.13, + 0.14, + 0.15, + 0.16, + 0.17, + 0.18, + 0.19, + 0.2, + 0.21, + 0.22, + 0.23, + 0.24, + 0.25, + 0.26, + 0.27, + 0.28, + 0.29, + 0.3, + 0.4, + 0.5, + 0.6, + 0.7, + 0.8, + 0.9, + ]: + SPARSE_CONFIGS.append( + ( + get_oracle_top_k_config_name(sink_size, window_size, top_k), + ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=sink_size), + LocalMaskerConfig(window_size=window_size), + OracleTopKConfig(heavy_size=top_k), + ] + ), + ) + ) # usa_weight_file = "/home/apd10/HashAttention-1.0/artifacts/llama3.1-8b-patch.64K.v1.pt" -weight_file = "/home/apd10/HashAttention-1.0/artifacts/llama3.1-8b-patch.64K.v1.hat_weights.pkl" +weight_file = ( + "/home/apd10/HashAttention-1.0/artifacts/llama3.1-8b-patch.64K.v1.hat_weights.pkl" +) # from sparse_attention_hub.sparse_attention.utils.hashattention_utils import create_hat_weights_file_from_usa -#create_hat_weights_file_from_usa(usa_weight_file, weight_file, num_layers=32, num_heads=32, device="cpu") +# create_hat_weights_file_from_usa(usa_weight_file, weight_file, num_layers=32, num_heads=32, device="cpu") # weight_dictionary = convert_usa_weights_to_hash_attention(weight_file, num_layers=32, num_heads=32, device="cpu") # hashattention + sink + window -for (sink_size, window_size) in [(0.001, 0.001), (0.005, 0.005), (0.01, 0.01), (0.02, 0.02)]: - for top_k in [0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.25, 0.3, 0.4, 0.5]: - SPARSE_CONFIGS.append((get_hashattention_config_name(sink_size, window_size, top_k), ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=sink_size), - LocalMaskerConfig(window_size=window_size), - HashAttentionTopKMaskerConfig(heavy_size=top_k, - hat_bits=32, - hat_mlp_layers=3, - hat_mlp_hidden_size=128, - hat_mlp_activation="silu", - hat_weight_file=weight_file, - hat_weights=None), - ]))) +for sink_size, window_size in [ + (0.001, 0.001), + (0.005, 0.005), + (0.01, 0.01), + (0.02, 0.02), +]: + for top_k in [ + 0.01, + 0.02, + 0.03, + 0.04, + 0.05, + 0.06, + 0.07, + 0.08, + 0.09, + 0.1, + 0.11, + 0.12, + 0.13, + 0.14, + 0.15, + 0.16, + 0.17, + 0.18, + 0.19, + 0.2, + 0.21, + 0.22, + 0.23, + 0.24, + 0.25, + 0.26, + 0.27, + 0.28, + 0.25, + 0.3, + 0.4, + 0.5, + ]: + SPARSE_CONFIGS.append( + ( + get_hashattention_config_name(sink_size, window_size, top_k), + ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=sink_size), + LocalMaskerConfig(window_size=window_size), + HashAttentionTopKMaskerConfig( + heavy_size=top_k, + hat_bits=32, + hat_mlp_layers=3, + hat_mlp_hidden_size=128, + hat_mlp_activation="silu", + hat_weight_file=weight_file, + hat_weights=None, + ), + ] + ), + ) + ) # adaptive sampling + hat top k + sink + window -for (epsilon, delta) in [(0.01, 0.01), (0.05, 0.05), (0.1, 0.1), (0.25, 0.25), (0.3, 0.3), (0.4, 0.4), (0.5, 0.5)]: - for (sink_size, window_size) in [(0.001, 0.001), (0.005, 0.005), (0.01, 0.01), (0.02, 0.02)]: +for epsilon, delta in [ + (0.01, 0.01), + (0.05, 0.05), + (0.1, 0.1), + (0.25, 0.25), + (0.3, 0.3), + (0.4, 0.4), + (0.5, 0.5), +]: + for sink_size, window_size in [ + (0.001, 0.001), + (0.005, 0.005), + (0.01, 0.01), + (0.02, 0.02), + ]: for heavy_size in [0.005, 0.01, 0.02, 0.05, 0.1]: for base_rate_sampling in [0.01, 0.05, 0.1]: - SPARSE_CONFIGS.append((get_adaptive_hat_config_name(sink_size, window_size, heavy_size, base_rate_sampling, epsilon, delta), ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=sink_size), - LocalMaskerConfig(window_size=window_size), - HashAttentionTopKMaskerConfig(heavy_size=heavy_size, - hat_bits=32, - hat_mlp_layers=3, - hat_mlp_hidden_size=128, - hat_mlp_activation="silu", - hat_weight_file=weight_file, - hat_weights=None), - AdaptiveSamplingMaskerConfig(base_rate_sampling=base_rate_sampling, epsilon=epsilon, delta=delta, init_offset=sink_size, local_offset=window_size) - ]))) + SPARSE_CONFIGS.append( + ( + get_adaptive_hat_config_name( + sink_size, + window_size, + heavy_size, + base_rate_sampling, + epsilon, + delta, + ), + ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=sink_size), + LocalMaskerConfig(window_size=window_size), + HashAttentionTopKMaskerConfig( + heavy_size=heavy_size, + hat_bits=32, + hat_mlp_layers=3, + hat_mlp_hidden_size=128, + hat_mlp_activation="silu", + hat_weight_file=weight_file, + hat_weights=None, + ), + AdaptiveSamplingMaskerConfig( + base_rate_sampling=base_rate_sampling, + epsilon=epsilon, + delta=delta, + init_offset=sink_size, + local_offset=window_size, + ), + ] + ), + ) + ) # random sampling + sink + window -for (epsilon, delta) in [(0.01, 0.01), (0.05, 0.05), (0.1, 0.1), (0.25, 0.25), (0.3, 0.3), (0.4, 0.4), (0.5, 0.5)]: - for (sink_size, window_size) in [(0.001, 0.001), (0.005, 0.005), (0.01, 0.01), (0.02, 0.02)]: +for epsilon, delta in [ + (0.01, 0.01), + (0.05, 0.05), + (0.1, 0.1), + (0.25, 0.25), + (0.3, 0.3), + (0.4, 0.4), + (0.5, 0.5), +]: + for sink_size, window_size in [ + (0.001, 0.001), + (0.005, 0.005), + (0.01, 0.01), + (0.02, 0.02), + ]: for sampling_rate in [0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5]: - SPARSE_CONFIGS.append((get_random_sampling_config_name(sink_size, window_size, sampling_rate), ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=sink_size), - LocalMaskerConfig(window_size=window_size), - RandomSamplingMaskerConfig(sampling_rate=sampling_rate) - ]))) - - -# + SPARSE_CONFIGS.append( + ( + get_random_sampling_config_name( + sink_size, window_size, sampling_rate + ), + ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=sink_size), + LocalMaskerConfig(window_size=window_size), + RandomSamplingMaskerConfig(sampling_rate=sampling_rate), + ] + ), + ) + ) + + +# print("total number of configs: ", len(SPARSE_CONFIGS)) # Benchmark List # 1. InfiniteBench - using passkey task infinite_bench_config = BenchmarkConfig( - benchmark_name="infinite_bench", - subsets=["passkey"] + benchmark_name="infinite_bench", subsets=["passkey"] ) # 2. Ruler - using 4096 context length -ruler_config = BenchmarkConfig( - benchmark_name="ruler", - subsets=["4096"] -) +ruler_config = BenchmarkConfig(benchmark_name="ruler", subsets=["4096"]) # 3. Loogle - using shortdep_qa task loogle_config = BenchmarkConfig( benchmark_name="loogle", - #subsets=["shortdep_qa"], + # subsets=["shortdep_qa"], subsets=["longdep_qa"], - #subsets=["shortdep_cloze"], - #subsets=["longdep_summarization"], + # subsets=["shortdep_cloze"], + # subsets=["longdep_summarization"], ) # 4. ZeroScrolls - using gov_report task zero_scrolls_config = BenchmarkConfig( - benchmark_name="zero_scrolls", - subsets=["default"] + benchmark_name="zero_scrolls", subsets=["default"] ) # 5. LongBenchv2 - using 0shot task -longbenchv2_config = BenchmarkConfig( - benchmark_name="longbenchv2", - subsets=["0shot"] -) +longbenchv2_config = BenchmarkConfig(benchmark_name="longbenchv2", subsets=["0shot"]) # 6. AIME2024 - using single task -aime2024_config = BenchmarkConfig( - benchmark_name="aime2024", - subsets=["aime2024"] -) +aime2024_config = BenchmarkConfig(benchmark_name="aime2024", subsets=["aime2024"]) # 7. AIME2025 - using single task -aime2025_config = BenchmarkConfig( - benchmark_name="aime2025", - subsets=["aime2025"] -) +aime2025_config = BenchmarkConfig(benchmark_name="aime2025", subsets=["aime2025"]) # 8. LongBench (existing) - using narrativeqa task longbench_config = BenchmarkConfig( - benchmark_name="longbench", - subsets=["passage_retrieval_en"] + benchmark_name="longbench", subsets=["passage_retrieval_en"] ) # 9. Mock Benchmark (existing) - using single task mock_benchmark_config = BenchmarkConfig( - benchmark_name="mock_benchmark", - subsets=["reading_comprehension"] + benchmark_name="mock_benchmark", subsets=["reading_comprehension"] ) # List of all sample configurations BENCHMARKS = [ - #infinite_bench_config, - #ruler_config, + # infinite_bench_config, + # ruler_config, loogle_config, - #zero_scrolls_config, - #longbenchv2_config, - #aime2024_config, - #aime2025_config, - #longbench_config, - #mock_benchmark_config + # zero_scrolls_config, + # longbenchv2_config, + # aime2024_config, + # aime2025_config, + # longbench_config, + # mock_benchmark_config ] @@ -231,7 +434,7 @@ def get_random_sampling_config_name(sink_size, window_size, sampling_rate): }, tokenizer_kwargs={ "padding_side": "left", - } + }, ) # Generation Parameters @@ -244,10 +447,7 @@ def get_random_sampling_config_name(sink_size, window_size, sampling_rate): } # Request Parameters -REQUEST_KWARGS = { - "max_context_length": 32000, - "max_requests": 1 -} +REQUEST_KWARGS = {"max_context_length": 32000, "max_requests": 1} # Execution Settings RESULT_DIR = "./stress_test_adaptive.matrix/" @@ -261,7 +461,7 @@ def get_random_sampling_config_name(sink_size, window_size, sampling_rate): if __name__ == "__main__": print("๐Ÿš€ Starting Minimalistic Benchmark Suite") print("=" * 50) - + print(f"๐Ÿ”ง Configuration:") print(f" - GPUs: {GPUS}") print(f" - Models: {len(MODELS)}") @@ -278,25 +478,29 @@ def get_random_sampling_config_name(sink_size, window_size, sampling_rate): print(f" - Benchmarks: {len(BENCHMARKS)}") for i, benchmark in enumerate(BENCHMARKS, 1): if benchmark.subsets: - print(f" {i}. {benchmark.benchmark_name}: {len(benchmark.subsets)} subsets") + print( + f" {i}. {benchmark.benchmark_name}: {len(benchmark.subsets)} subsets" + ) else: print(f" {i}. {benchmark.benchmark_name}: all subsets") print(f" - Max concurrent: {MAX_CONCURRENT_RUNS}") print(f" - Result dir: {RESULT_DIR}") print(f" - Resumability: {'enabled' if ENABLE_RESUMABILITY else 'disabled'}") - + # Calculate total combinations total_models = len(MODELS) total_configs = len(SPARSE_CONFIGS) total_benchmarks = sum(len(b.subsets) if b.subsets else 1 for b in BENCHMARKS) total_combinations = total_models * total_configs * total_benchmarks - + print(f"\n๐Ÿ“Š Experiment Matrix: {total_combinations} total combinations") print(f" - Models: {total_models}") print(f" - Sparse configs: {total_configs}") print(f" - Benchmark-subsets: {total_benchmarks}") - print(f" - Estimated time: {total_combinations * TIMEOUT_PER_BENCHMARK / 3600:.1f} hours (worst case)") - + print( + f" - Estimated time: {total_combinations * TIMEOUT_PER_BENCHMARK / 3600:.1f} hours (worst case)" + ) + # Create executor print(f"\n๐Ÿ”ง Initializing BenchmarkExecutor...") executor = BenchmarkExecutor( @@ -306,9 +510,9 @@ def get_random_sampling_config_name(sink_size, window_size, sampling_rate): enable_resumability=ENABLE_RESUMABILITY, required_result_files=["raw_results.csv"], timeout_per_benchmark=TIMEOUT_PER_BENCHMARK, - verbose=True + verbose=True, ) - + # Run benchmarks print(f"\n๐ŸŽฏ Running Benchmark Matrix...") try: @@ -318,9 +522,9 @@ def get_random_sampling_config_name(sink_size, window_size, sampling_rate): benchmark_configs=BENCHMARKS, adapter_config=ADAPTER_CONFIG, generation_kwargs=GENERATION_KWARGS, - request_kwargs=REQUEST_KWARGS + request_kwargs=REQUEST_KWARGS, ) - + # Print summary print(f"\nโœ… Benchmark Execution Completed!") print(f" - Total: {results.progress.total_stubs}") @@ -328,10 +532,10 @@ def get_random_sampling_config_name(sink_size, window_size, sampling_rate): print(f" - Failed: {results.progress.failed_stubs}") print(f" - Skipped: {results.progress.skipped_stubs}") print(f" - Results saved to: {RESULT_DIR}") - + except KeyboardInterrupt: print(f"\nโš ๏ธ Interrupted by user") print(f" Partial results in: {RESULT_DIR}") except Exception as e: print(f"\nโŒ Execution failed: {e}") - raise + raise diff --git a/benchmark/scripts/single_benchmark_model_example.py b/benchmark/scripts/single_benchmark_model_example.py index b0418fc1..f5c014eb 100644 --- a/benchmark/scripts/single_benchmark_model_example.py +++ b/benchmark/scripts/single_benchmark_model_example.py @@ -24,46 +24,64 @@ import sys # Change to directory two levels below current location -os.chdir('/workspace/sparse-attention-hub') -sys.path.insert(0, '/workspace/sparse-attention-hub') +os.chdir("/workspace/sparse-attention-hub") +sys.path.insert(0, "/workspace/sparse-attention-hub") -from sparse_attention_hub.sparse_attention.research_attention import ResearchAttentionConfig +from sparse_attention_hub.sparse_attention.research_attention import ( + ResearchAttentionConfig, +) from sparse_attention_hub.sparse_attention.research_attention.maskers.fixed.implementations import ( - LocalMaskerConfig, SinkMaskerConfig, OracleTopKConfig + LocalMaskerConfig, + SinkMaskerConfig, + OracleTopKConfig, ) from sparse_attention_hub.sparse_attention.research_attention.maskers.sampling.implementations import ( - AdaptiveSamplingMaskerConfig + AdaptiveSamplingMaskerConfig, ) from benchmark.ruler32k import Ruler32K from sparse_attention_hub.adapters import ModelAdapterHF + def main(): model_name = "meta-llama/Llama-3.1-8B-Instruct" - device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') - - sparse_attention_config = ResearchAttentionConfig(masker_configs=[ - SinkMaskerConfig(sink_size=128), - LocalMaskerConfig(window_size=128), - OracleTopKConfig(heavy_size=128), - AdaptiveSamplingMaskerConfig(base_rate_sampling=0.05, epsilon=0.25, delta=0.25, init_offset=128, local_offset=128) - ]) - + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + sparse_attention_config = ResearchAttentionConfig( + masker_configs=[ + SinkMaskerConfig(sink_size=128), + LocalMaskerConfig(window_size=128), + OracleTopKConfig(heavy_size=128), + AdaptiveSamplingMaskerConfig( + base_rate_sampling=0.05, + epsilon=0.25, + delta=0.25, + init_offset=128, + local_offset=128, + ), + ] + ) + print(" โœ“ Loading model...") adapter = ModelAdapterHF( model_name=model_name, sparse_attention_config=sparse_attention_config, - model_kwargs= {"torch_dtype": torch.bfloat16}, + model_kwargs={"torch_dtype": torch.bfloat16}, generate_kwargs={"max_new_tokens": 32}, - device=device + device=device, ) - - benchmark = Ruler32K(['vt']) + + benchmark = Ruler32K(["vt"]) result_dir = Path("./test_results") result_dir.mkdir(exist_ok=True) - benchmark.run_benchmark(adapter, result_dir, request_kwargs={"max_requests": 1, "max_context_length": 1000000}) - + benchmark.run_benchmark( + adapter, + result_dir, + request_kwargs={"max_requests": 1, "max_context_length": 1000000}, + ) + + if __name__ == "__main__": - main() + main() diff --git a/benchmark/utils/__init__.py b/benchmark/utils/__init__.py index c6afe576..b5da8152 100644 --- a/benchmark/utils/__init__.py +++ b/benchmark/utils/__init__.py @@ -12,7 +12,7 @@ construct_result_directory, create_result_directory, validate_result_directory_path, - ensure_result_directory + ensure_result_directory, ) from .gpu import ( @@ -21,24 +21,19 @@ acquire_gpu_from_pool, release_gpu_to_pool, validate_gpu_for_model, - cleanup_gpu_memory + cleanup_gpu_memory, ) -from .data import ( - escape_dataframe_for_csv, - save_dataframe_to_csv, - make_serializable -) +from .data import escape_dataframe_for_csv, save_dataframe_to_csv, make_serializable # Re-export all utilities for backward compatibility __all__ = [ # Path utilities "sanitize_model_name", - "construct_result_directory", + "construct_result_directory", "create_result_directory", "validate_result_directory_path", "ensure_result_directory", - # GPU utilities "validate_gpu_availability", "create_gpu_pool", @@ -46,9 +41,8 @@ "release_gpu_to_pool", "validate_gpu_for_model", "cleanup_gpu_memory", - # Data utilities "escape_dataframe_for_csv", "save_dataframe_to_csv", - "make_serializable" -] \ No newline at end of file + "make_serializable", +] diff --git a/benchmark/utils/data.py b/benchmark/utils/data.py index 20791831..7d161ac9 100644 --- a/benchmark/utils/data.py +++ b/benchmark/utils/data.py @@ -13,13 +13,13 @@ def make_serializable(obj: Any) -> Any: """Convert non-serializable objects to strings recursively, including dataclasses. - + Args: obj: Object to make JSON serializable - + Returns: JSON serializable version of the object - + Example: >>> config = {"torch_dtype": torch.bfloat16, "device": "cuda"} >>> serializable = make_serializable(config) @@ -29,13 +29,13 @@ def make_serializable(obj: Any) -> Any: return {k: make_serializable(v) for k, v in dataclasses.asdict(obj).items()} if isinstance(obj, (torch.dtype, torch.device)): return str(obj) - elif hasattr(obj, 'dtype'): + elif hasattr(obj, "dtype"): return str(obj) elif isinstance(obj, dict): return {k: make_serializable(v) for k, v in obj.items()} elif isinstance(obj, (list, tuple)): return [make_serializable(item) for item in obj] - elif hasattr(obj, '__dict__'): + elif hasattr(obj, "__dict__"): # For custom objects return make_serializable(vars(obj)) elif obj is None: @@ -50,16 +50,16 @@ def make_serializable(obj: Any) -> Any: def escape_dataframe_for_csv(df: pd.DataFrame) -> pd.DataFrame: """Escape special characters in DataFrame for safe CSV export. - + This function prepares a DataFrame for CSV export by escaping newlines, carriage returns, and other special characters that could cause parsing issues. - + Args: df: DataFrame to escape - + Returns: DataFrame with escaped string columns - + Example: >>> df = pd.DataFrame({ ... 'text': ['Line 1\nLine 2', 'Text with, comma'] @@ -68,34 +68,36 @@ def escape_dataframe_for_csv(df: pd.DataFrame) -> pd.DataFrame: >>> escaped_df.to_csv('output.csv', quoting=csv.QUOTE_ALL) """ escaped_df = df.copy() - + for col in escaped_df.columns: - if escaped_df[col].dtype == 'object': # Only process string columns - escaped_df[col] = escaped_df[col].astype(str).str.replace('\n', '\\n').str.replace('\r', '\\r') - + if escaped_df[col].dtype == "object": # Only process string columns + escaped_df[col] = ( + escaped_df[col] + .astype(str) + .str.replace("\n", "\\n") + .str.replace("\r", "\\r") + ) + return escaped_df def save_dataframe_to_csv( - df: pd.DataFrame, - file_path: str, - index: bool = False, - quoting: int = csv.QUOTE_ALL + df: pd.DataFrame, file_path: str, index: bool = False, quoting: int = csv.QUOTE_ALL ) -> None: """Save DataFrame to CSV with proper escaping and quoting. - + This is a convenience function that combines escaping and CSV export with consistent settings for benchmark results. - + Args: df: DataFrame to save file_path: Path to save the CSV file index: Whether to include DataFrame index in output quoting: CSV quoting mode (default: QUOTE_ALL) - + Example: >>> df = pd.DataFrame({'text': ['Line 1\nLine 2']}) >>> save_dataframe_to_csv(df, 'results.csv') """ escaped_df = escape_dataframe_for_csv(df) - escaped_df.to_csv(file_path, index=index, quoting=quoting) \ No newline at end of file + escaped_df.to_csv(file_path, index=index, quoting=quoting) diff --git a/benchmark/utils/gpu.py b/benchmark/utils/gpu.py index 84fd2cf6..cefd4053 100644 --- a/benchmark/utils/gpu.py +++ b/benchmark/utils/gpu.py @@ -19,7 +19,7 @@ def get_cuda_visible_devices() -> List[int]: """Get the CUDA_VISIBLE_DEVICES environment variable. - + Returns: CUDA_VISIBLE_DEVICES environment variable, or None if not set """ @@ -32,39 +32,39 @@ def get_cuda_visible_devices() -> List[int]: def validate_gpu_availability(gpu_ids: List[int]) -> None: """Validate that specified GPUs are available and accessible. - + Checks that CUDA is available, GPUs exist, and they are accessible. - + Args: gpu_ids: List of GPU device IDs to validate - + Raises: RuntimeError: If CUDA is not available ValueError: If any GPU ID is invalid or inaccessible OSError: If GPU access fails - + Example: >>> validate_gpu_availability([0, 1]) # Validates GPUs 0 and 1 >>> # No exception means GPUs are available """ if not torch.cuda.is_available(): raise RuntimeError("CUDA is not available") - + if not gpu_ids: raise ValueError("gpu_ids cannot be empty") - + num_gpus: int = torch.cuda.device_count() if num_gpus == 0: raise RuntimeError("No CUDA devices found") - + # Check each GPU ID for gpu_id in gpu_ids: if not isinstance(gpu_id, int) or gpu_id < 0: raise ValueError(f"Invalid GPU ID: {gpu_id}") - + # if gpu_id >= num_gpus: # raise ValueError(f"GPU {gpu_id} does not exist. Available GPUs: 0-{num_gpus-1}") - + # Test GPU access try: with torch.cuda.device(gpu_id): @@ -76,17 +76,17 @@ def validate_gpu_availability(gpu_ids: List[int]) -> None: raise OSError(f"Cannot access GPU {gpu_id}: {e}") from e -def create_gpu_pool(gpu_ids: List[int]) -> 'multiprocessing.Queue[int]': +def create_gpu_pool(gpu_ids: List[int]) -> "multiprocessing.Queue[int]": """Create a multiprocessing queue to manage GPU access. - + Creates a thread-safe queue that workers can use to acquire and release GPUs. - + Args: gpu_ids: List of GPU device IDs to include in the pool - + Returns: Multiprocessing queue containing available GPU IDs - + Example: >>> gpu_pool = create_gpu_pool([0, 1, 2]) >>> gpu_id = acquire_gpu_from_pool(gpu_pool) @@ -94,30 +94,32 @@ def create_gpu_pool(gpu_ids: List[int]) -> 'multiprocessing.Queue[int]': >>> release_gpu_to_pool(gpu_pool, gpu_id) """ validate_gpu_availability(gpu_ids) - + # Create queue and populate with GPU IDs - gpu_pool: 'multiprocessing.Queue[int]' = multiprocessing.Queue() + gpu_pool: "multiprocessing.Queue[int]" = multiprocessing.Queue() for gpu_id in gpu_ids: gpu_pool.put(gpu_id) - + return gpu_pool -def acquire_gpu_from_pool(gpu_pool: 'multiprocessing.Queue[int]', timeout: float = 30.0) -> int: +def acquire_gpu_from_pool( + gpu_pool: "multiprocessing.Queue[int]", timeout: float = 30.0 +) -> int: """Acquire a GPU from the pool with timeout. - + Blocks until a GPU becomes available or timeout is reached. - + Args: gpu_pool: GPU pool queue timeout: Maximum time to wait for GPU in seconds - + Returns: GPU device ID that was acquired - + Raises: queue.Empty: If no GPU becomes available within timeout - + Example: >>> gpu_id = acquire_gpu_from_pool(gpu_pool, timeout=60.0) >>> print(f"Acquired GPU {gpu_id}") @@ -129,15 +131,15 @@ def acquire_gpu_from_pool(gpu_pool: 'multiprocessing.Queue[int]', timeout: float raise queue.Empty(f"No GPU available within {timeout} seconds") -def release_gpu_to_pool(gpu_pool: 'multiprocessing.Queue[int]', gpu_id: int) -> None: +def release_gpu_to_pool(gpu_pool: "multiprocessing.Queue[int]", gpu_id: int) -> None: """Release a GPU back to the pool. - + Returns the GPU to the pool so other workers can use it. - + Args: gpu_pool: GPU pool queue gpu_id: GPU device ID to release - + Example: >>> release_gpu_to_pool(gpu_pool, 0) >>> # GPU 0 is now available for other workers @@ -145,23 +147,25 @@ def release_gpu_to_pool(gpu_pool: 'multiprocessing.Queue[int]', gpu_id: int) -> gpu_pool.put(gpu_id) -def validate_gpu_for_model(gpu_id: int, model_name: str, check_memory: bool = True) -> Dict[str, Any]: +def validate_gpu_for_model( + gpu_id: int, model_name: str, check_memory: bool = True +) -> Dict[str, Any]: """Validate that a GPU is suitable for running a specific model. - + Performs various checks including memory availability and compute capability. - + Args: gpu_id: GPU device ID to validate model_name: Name of the model (for logging purposes) check_memory: Whether to check available GPU memory - + Returns: Dictionary containing validation results and GPU information - + Raises: ValueError: If GPU is not suitable for the model OSError: If GPU access fails - + Example: >>> info = validate_gpu_for_model(0, "llama-7b") >>> print(f"GPU memory: {info['memory_gb']} GB") @@ -170,11 +174,13 @@ def validate_gpu_for_model(gpu_id: int, model_name: str, check_memory: bool = Tr with torch.cuda.device(gpu_id): # Get GPU properties props = torch.cuda.get_device_properties(gpu_id) - + # Basic validation if props.major < 7: # Require compute capability 7.0+ - raise ValueError(f"GPU {gpu_id} has insufficient compute capability: {props.major}.{props.minor}") - + raise ValueError( + f"GPU {gpu_id} has insufficient compute capability: {props.major}.{props.minor}" + ) + # Memory validation memory_info: Dict[str, Any] = {} if check_memory: @@ -182,40 +188,39 @@ def validate_gpu_for_model(gpu_id: int, model_name: str, check_memory: bool = Tr allocated_memory = torch.cuda.memory_allocated(gpu_id) / (1024**3) cached_memory = torch.cuda.memory_reserved(gpu_id) / (1024**3) free_memory = total_memory - allocated_memory - + memory_info = { "total_gb": total_memory, "allocated_gb": allocated_memory, "cached_gb": cached_memory, - "free_gb": free_memory + "free_gb": free_memory, } - + # Warn if memory is low (less than 2GB free) if free_memory < 2.0: logging.warning( f"GPU {gpu_id} has low memory for {model_name}: " f"{free_memory:.1f}GB free out of {total_memory:.1f}GB total" ) - + return { "gpu_id": gpu_id, "name": props.name, "compute_capability": f"{props.major}.{props.minor}", "memory_gb": props.total_memory / (1024**3), - **memory_info + **memory_info, } - + except Exception as e: raise OSError(f"Failed to validate GPU {gpu_id} for {model_name}: {e}") from e - def cleanup_gpu_memory(gpu_id: Optional[int] = None) -> None: """Clean up GPU memory by emptying CUDA cache. - + Args: gpu_id: Specific GPU to clean up, or None for current device - + Example: >>> cleanup_gpu_memory(0) # Clean up GPU 0 >>> cleanup_gpu_memory() # Clean up current device @@ -225,4 +230,4 @@ def cleanup_gpu_memory(gpu_id: Optional[int] = None) -> None: with torch.cuda.device(gpu_id): torch.cuda.empty_cache() else: - torch.cuda.empty_cache() \ No newline at end of file + torch.cuda.empty_cache() diff --git a/benchmark/utils/paths.py b/benchmark/utils/paths.py index 9b541f5e..3e355de8 100644 --- a/benchmark/utils/paths.py +++ b/benchmark/utils/paths.py @@ -15,16 +15,16 @@ def sanitize_model_name(model_name: str) -> str: """Sanitize model name for use in directory paths. - + Replaces special characters that are not filesystem-safe with underscores. This ensures model names can be used as directory names across different operating systems. - + Args: model_name: Original model name (e.g., "meta-llama/Llama-3.1-8B-Instruct") - + Returns: Sanitized model name safe for filesystem use - + Example: >>> sanitized = sanitize_model_name("meta-llama/Llama-3.1-8B-Instruct") >>> print(sanitized) @@ -32,18 +32,18 @@ def sanitize_model_name(model_name: str) -> str: """ # Characters that need to be replaced: / \ : * ? " < > | special_chars: str = r'\/\:*?"<>|' - + sanitized: str = model_name for char in special_chars: - sanitized = sanitized.replace(char, '_') - + sanitized = sanitized.replace(char, "_") + # Remove multiple consecutive underscores - while '__' in sanitized: - sanitized = sanitized.replace('__', '_') - + while "__" in sanitized: + sanitized = sanitized.replace("__", "_") + # Remove leading/trailing underscores - sanitized = sanitized.strip('_') - + sanitized = sanitized.strip("_") + return sanitized @@ -52,103 +52,102 @@ def construct_result_directory( model_name: str, sparse_config_name: str, benchmark_name: str, - subset: Optional[str] = None + subset: Optional[str] = None, ) -> str: """Construct result directory path following the standard hierarchy. - + Creates a path following the pattern: base_dir/sanitized_model/sparse_config/benchmark_subset/ - + Note: No timestamp in path to enable resumability across runs. - + Args: base_result_dir: Base directory for all benchmark results model_name: Original model name (will be sanitized) sparse_config_name: Name of sparse attention configuration benchmark_name: Name of the benchmark subset: Optional subset name (appended to benchmark_name with underscore) - + Returns: Complete path to result directory - + Example: >>> path = construct_result_directory( - ... "./results", "meta-llama/Llama-3.1-8B", + ... "./results", "meta-llama/Llama-3.1-8B", ... "dense", "longbench", "narrativeqa" ... ) >>> print(path) "./results/meta_llama_Llama_3.1_8B/dense/longbench_narrativeqa" """ sanitized_model: str = sanitize_model_name(model_name) - + # Construct benchmark directory name benchmark_dir: str = benchmark_name if subset is not None: benchmark_dir = f"{benchmark_name}_{subset}" - + # Build path components (no timestamp for resumability) path_components: list[str] = [ base_result_dir, sanitized_model, sparse_config_name, - benchmark_dir + benchmark_dir, ] - + result_path: str = os.path.join(*path_components) return str(Path(result_path).resolve()) -def create_result_directory( - result_dir: str, - create_parents: bool = True -) -> bool: +def create_result_directory(result_dir: str, create_parents: bool = True) -> bool: """Create result directory with proper error handling. - + Creates the specified directory and all necessary parent directories. This function is safe to call multiple times on the same path. - + Args: result_dir: Path to the directory to create create_parents: Whether to create parent directories if they don't exist - + Returns: True if directory was created or already exists, False if creation failed - + Raises: ValueError: If result_dir is empty or invalid PermissionError: If insufficient permissions to create directory OSError: If directory creation fails for other reasons - + Example: >>> success = create_result_directory("/path/to/results/model_experiment") >>> print(success) # True if successful """ if not result_dir or not result_dir.strip(): raise ValueError("result_dir cannot be empty") - + result_path = Path(result_dir.strip()) - + try: # Create directory and parents if needed result_path.mkdir(parents=create_parents, exist_ok=True) - + # Verify directory was created and is writable if not result_path.exists(): return False - + if not result_path.is_dir(): raise OSError(f"Path exists but is not a directory: {result_path}") - + # Test write permissions by creating a temporary file test_file = result_path / ".write_test" try: test_file.touch() test_file.unlink() # Remove test file except (PermissionError, OSError) as e: - raise PermissionError(f"Directory created but not writable: {result_path}") from e - + raise PermissionError( + f"Directory created but not writable: {result_path}" + ) from e + return True - + except PermissionError: raise except OSError as e: @@ -156,43 +155,42 @@ def create_result_directory( def validate_result_directory_path( - result_dir: str, - check_parent_writable: bool = True + result_dir: str, check_parent_writable: bool = True ) -> None: """Validate that a result directory path is valid and can be created. - + Performs validation without actually creating the directory. - + Args: result_dir: Path to validate check_parent_writable: Whether to check if parent directory is writable - + Raises: ValueError: If path is invalid or unsafe PermissionError: If parent directory is not writable OSError: If path validation fails - + Example: >>> validate_result_directory_path("/path/to/results") >>> # No exception means path is valid """ if not result_dir or not result_dir.strip(): raise ValueError("result_dir cannot be empty") - + result_path = Path(result_dir.strip()) - + # Check for unsafe path components try: result_path.resolve() except (OSError, RuntimeError) as e: raise ValueError(f"Invalid path: {result_dir}") from e - + # Check if path already exists if result_path.exists(): if not result_path.is_dir(): raise OSError(f"Path exists but is not a directory: {result_path}") return # Directory exists and is valid - + # Check parent directory parent_path = result_path.parent if not parent_path.exists(): @@ -205,38 +203,37 @@ def validate_result_directory_path( test_file.touch() test_file.unlink() except (PermissionError, OSError) as e: - raise PermissionError(f"Parent directory not writable: {parent_path}") from e + raise PermissionError( + f"Parent directory not writable: {parent_path}" + ) from e -def ensure_result_directory( - result_dir: str, - validate_first: bool = True -) -> str: +def ensure_result_directory(result_dir: str, validate_first: bool = True) -> str: """Ensure result directory exists, creating it if necessary. - + This is a convenience function that combines validation and creation. - + Args: result_dir: Path to the result directory validate_first: Whether to validate before creating - + Returns: Absolute path to the result directory - + Raises: ValueError: If path is invalid PermissionError: If directory cannot be created due to permissions OSError: If directory creation fails - + Example: >>> path = ensure_result_directory("/path/to/results") >>> print(path) # "/absolute/path/to/results" """ if validate_first: validate_result_directory_path(result_dir) - + success = create_result_directory(result_dir) if not success: raise OSError(f"Failed to create result directory: {result_dir}") - - return str(Path(result_dir).resolve()) \ No newline at end of file + + return str(Path(result_dir).resolve()) diff --git a/benchmark/zero_scrolls/create_huggingface_dataset.py b/benchmark/zero_scrolls/create_huggingface_dataset.py index 7e3e9d45..997f98d4 100644 --- a/benchmark/zero_scrolls/create_huggingface_dataset.py +++ b/benchmark/zero_scrolls/create_huggingface_dataset.py @@ -22,8 +22,12 @@ for task, max_new_tokens in MAX_NEW_TOKENS.items(): df = load_dataset("tau/zero_scrolls", task, split="test").to_pandas() df["context"] = df.apply(lambda x: x["input"][: x["document_end_index"]], axis=1) - df["question"] = df.apply(lambda x: x["input"][x["document_end_index"] : x["query_end_index"]], axis=1) - df["answer_prefix"] = df.apply(lambda x: x["input"][x["query_end_index"] :], axis=1).str.strip() + df["question"] = df.apply( + lambda x: x["input"][x["document_end_index"] : x["query_end_index"]], axis=1 + ) + df["answer_prefix"] = df.apply( + lambda x: x["input"][x["query_end_index"] :], axis=1 + ).str.strip() df["answer"] = "" df["task"] = task df["max_new_tokens"] = max_new_tokens diff --git a/benchmark/zero_scrolls/zero_scrolls.py b/benchmark/zero_scrolls/zero_scrolls.py index 95993d03..c178d2a7 100644 --- a/benchmark/zero_scrolls/zero_scrolls.py +++ b/benchmark/zero_scrolls/zero_scrolls.py @@ -40,46 +40,61 @@ class ZeroScrolls(Benchmark): # "book_sum_sort" # ] # all tasks are clubbed into a single subset on huggingface - all_datasets: List[str] = [ "default"] - + all_datasets: List[str] = ["default"] + benchmark_name: str = "zero_scrolls" huggingface_dataset_id: str = "simonjegou/zero_scrolls" def _load_datasets(self) -> pd.DataFrame: """Load ZeroScrolls datasets by individual configs. - + ZeroScrolls requires loading each subset as a separate config. - + Returns: Combined pandas DataFrame with all samples from subsets_to_run. """ print(f"Loading ZeroScrolls datasets: {self.subsets_to_run}") dfs = [] - + for subset in self.subsets_to_run: try: from datasets import load_dataset - subset_dataset = load_dataset(self.huggingface_dataset_id, subset, split="test") + + subset_dataset = load_dataset( + self.huggingface_dataset_id, subset, split="test" + ) subset_df = subset_dataset.to_pandas() - + # Process the data according to ZeroScrolls format - subset_df["context"] = subset_df.apply(lambda x: x["input"][: x["document_end_index"]], axis=1) - subset_df["question"] = subset_df.apply(lambda x: x["input"][x["document_end_index"] : x["query_end_index"]], axis=1) - subset_df["answer_prefix"] = subset_df.apply(lambda x: x["input"][x["query_end_index"] :], axis=1).str.strip() - subset_df["answer"] = "" # ZeroScrolls doesn't provide ground truth answers + subset_df["context"] = subset_df.apply( + lambda x: x["input"][: x["document_end_index"]], axis=1 + ) + subset_df["question"] = subset_df.apply( + lambda x: x["input"][ + x["document_end_index"] : x["query_end_index"] + ], + axis=1, + ) + subset_df["answer_prefix"] = subset_df.apply( + lambda x: x["input"][x["query_end_index"] :], axis=1 + ).str.strip() + subset_df["answer"] = ( + "" # ZeroScrolls doesn't provide ground truth answers + ) subset_df["task"] = subset - + dfs.append(subset_df) print(f" โœ“ Loaded {len(subset_df)} samples from {subset}") except Exception as subset_error: print(f" โŒ Failed to load {subset}: {str(subset_error)}") continue - + if not dfs: raise Exception("No ZeroScrolls subsets could be loaded successfully") - + # Combine all subset DataFrames import pandas as pd + combined_df = pd.concat(dfs, ignore_index=True) print(f"Combined {len(combined_df)} total samples from {len(dfs)} subsets") return combined_df @@ -104,23 +119,25 @@ def post_run_evaluate(self, results_df: pd.DataFrame) -> Dict[str, Any]: # Group results by task task_groups = results_df.groupby("task") task_stats: Dict[str, Dict[str, Any]] = {} - + for task_name, task_df in task_groups: # Calculate basic statistics since no ground truth is available - avg_length = task_df["predicted_answer"].str.len().mean() if len(task_df) > 0 else 0 + avg_length = ( + task_df["predicted_answer"].str.len().mean() if len(task_df) > 0 else 0 + ) task_stats[task_name] = { "num_samples": len(task_df), "avg_response_length": round(avg_length, 2), - "note": "No ground truth available for evaluation" + "note": "No ground truth available for evaluation", } - + overall_metrics: Dict[str, Any] = { "task_stats": task_stats, "summary": { "total_tasks": len(task_stats), "total_samples": len(results_df), - "note": "ZeroScrolls benchmark completed. No ground truth available for scoring." - } + "note": "ZeroScrolls benchmark completed. No ground truth available for scoring.", + }, } - - return overall_metrics + + return overall_metrics diff --git a/cursor_chats/plans/sample_benchmark_configs.py b/cursor_chats/plans/sample_benchmark_configs.py index c3d16b0a..3c51005b 100644 --- a/cursor_chats/plans/sample_benchmark_configs.py +++ b/cursor_chats/plans/sample_benchmark_configs.py @@ -10,56 +10,35 @@ # 1. InfiniteBench - using passkey task infinite_bench_config = BenchmarkConfig( - benchmark_name="infinite_bench", - subsets=["passkey"] + benchmark_name="infinite_bench", subsets=["passkey"] ) # 2. Ruler - using 4096 context length -ruler_config = BenchmarkConfig( - benchmark_name="ruler", - subsets=["4096"] -) +ruler_config = BenchmarkConfig(benchmark_name="ruler", subsets=["4096"]) # 3. Loogle - using shortdep_qa task -loogle_config = BenchmarkConfig( - benchmark_name="loogle", - subsets=["shortdep_qa"] -) +loogle_config = BenchmarkConfig(benchmark_name="loogle", subsets=["shortdep_qa"]) # 4. ZeroScrolls - using gov_report task zero_scrolls_config = BenchmarkConfig( - benchmark_name="zero_scrolls", - subsets=["gov_report"] + benchmark_name="zero_scrolls", subsets=["gov_report"] ) # 5. LongBenchv2 - using 0shot task -longbenchv2_config = BenchmarkConfig( - benchmark_name="longbenchv2", - subsets=["0shot"] -) +longbenchv2_config = BenchmarkConfig(benchmark_name="longbenchv2", subsets=["0shot"]) # 6. AIME2024 - using single task -aime2024_config = BenchmarkConfig( - benchmark_name="aime2024", - subsets=["aime2024"] -) +aime2024_config = BenchmarkConfig(benchmark_name="aime2024", subsets=["aime2024"]) # 7. AIME2025 - using single task -aime2025_config = BenchmarkConfig( - benchmark_name="aime2025", - subsets=["aime2025"] -) +aime2025_config = BenchmarkConfig(benchmark_name="aime2025", subsets=["aime2025"]) # 8. LongBench (existing) - using narrativeqa task -longbench_config = BenchmarkConfig( - benchmark_name="longbench", - subsets=["narrativeqa"] -) +longbench_config = BenchmarkConfig(benchmark_name="longbench", subsets=["narrativeqa"]) # 9. Mock Benchmark (existing) - using single task mock_benchmark_config = BenchmarkConfig( - benchmark_name="mock_benchmark", - subsets=["mock_task"] + benchmark_name="mock_benchmark", subsets=["mock_task"] ) # List of all sample configurations @@ -72,33 +51,35 @@ aime2024_config, aime2025_config, longbench_config, - mock_benchmark_config + mock_benchmark_config, ] + # Example usage with executor def get_sample_configs(): """Return all sample benchmark configurations. - + Returns: List of BenchmarkConfig instances, one for each benchmark with a single subset. """ return all_sample_configs + # Example of how to use these configurations if __name__ == "__main__": print("Sample BenchmarkConfigs for all benchmarks:") print("=" * 50) - + for config in all_sample_configs: print(f"Benchmark: {config.benchmark_name}") print(f"Subsets: {config.subsets}") print("-" * 30) - + print(f"\nTotal configurations: {len(all_sample_configs)}") - + # Example of validation from benchmark.benchmark_registry import create_benchmark_instance - + print("\nValidating configurations...") for config in all_sample_configs: try: @@ -106,4 +87,4 @@ def get_sample_configs(): config.validate_with_benchmark_instance(benchmark) print(f"โœ… {config.benchmark_name}: Valid") except Exception as e: - print(f"โŒ {config.benchmark_name}: {str(e)}") \ No newline at end of file + print(f"โŒ {config.benchmark_name}: {str(e)}") diff --git a/sparse_attention_hub/metric_logging/logger.py b/sparse_attention_hub/metric_logging/logger.py index a42bc53b..a6788008 100644 --- a/sparse_attention_hub/metric_logging/logger.py +++ b/sparse_attention_hub/metric_logging/logger.py @@ -14,7 +14,7 @@ @dataclass class LogEvent: """Log event data structure for metric logging. - + Attributes: timestamp: When the event was logged. metric: Metric identifier string. @@ -32,11 +32,11 @@ class LogEvent: class MicroMetricLogger: """Singleton logger for micro metrics with queue-based architecture. - + This class provides a singleton pattern for logging micro metrics during sparse attention operations. It supports metric registration, sampling, and configurable limits on record count and flush behavior. - + Attributes: log_path: Optional directory path where log files will be written. flush_every: Number of events after which to flush to disk. @@ -64,7 +64,7 @@ def __init__( sampling_factor: float = 1.0, ) -> None: """Initialize the MicroMetricLogger. - + Args: log_path: Optional directory path where log files will be written. flush_every: Number of events after which to flush to disk. @@ -75,8 +75,12 @@ def __init__( """ if not self._initialized: self._initialize_logger( - log_path, flush_every, flush_interval, - enabled_metrics, max_records, sampling_factor + log_path, + flush_every, + flush_interval, + enabled_metrics, + max_records, + sampling_factor, ) else: self._handle_reinitialization(log_path) @@ -91,7 +95,7 @@ def _initialize_logger( sampling_factor: float, ) -> None: """Initialize logger instance for the first time. - + Args: log_path: Directory path for log files. flush_every: Number of events before flushing. @@ -100,7 +104,9 @@ def _initialize_logger( max_records: Maximum records limit. sampling_factor: Event sampling probability. """ - self._set_configuration(log_path, flush_every, flush_interval, max_records, sampling_factor) + self._set_configuration( + log_path, flush_every, flush_interval, max_records, sampling_factor + ) self._initialize_state() self._configure_logging_if_needed(log_path, enabled_metrics) MicroMetricLogger._initialized = True @@ -114,7 +120,7 @@ def _set_configuration( sampling_factor: float, ) -> None: """Set logger configuration parameters. - + Args: log_path: Directory path for log files. flush_every: Number of events before flushing. @@ -136,12 +142,10 @@ def _initialize_state(self) -> None: self._total_records_logged: int = 0 def _configure_logging_if_needed( - self, - log_path: Optional[str], - enabled_metrics: Union[List[str], str, None] + self, log_path: Optional[str], enabled_metrics: Union[List[str], str, None] ) -> None: """Configure logging if log path is provided. - + Args: log_path: Directory path for log files. enabled_metrics: Metrics to enable initially. @@ -152,7 +156,7 @@ def _configure_logging_if_needed( def _handle_reinitialization(self, log_path: Optional[str]) -> None: """Handle warning when logger is reinitialized. - + Args: log_path: New log path being requested. """ @@ -178,7 +182,7 @@ def register_metric(cls, identifier: str, dtype: type) -> None: @classmethod def get_registered_metrics(cls) -> Dict[str, type]: """Get all registered metrics at class level. - + Returns: Dictionary mapping metric identifiers to their expected data types. """ @@ -191,7 +195,7 @@ def _ensure_log_directory(self) -> None: def _get_calling_location(self) -> str: """Get the calling location using inspect module. - + Returns: String representation of the calling location in format "module.class.method" or "module.function". @@ -214,10 +218,10 @@ def _get_calling_location(self) -> str: def _get_module_name(self, frame: Any) -> str: """Get module name from frame. - + Args: frame: Stack frame object. - + Returns: Module name or "unknown" if not available. """ @@ -226,10 +230,10 @@ def _get_module_name(self, frame: Any) -> str: def _get_class_name(self, frame: Any) -> Optional[str]: """Get class name from frame if it's a method call. - + Args: frame: Stack frame object. - + Returns: Class name if available, None otherwise. """ @@ -245,7 +249,7 @@ def enable_metrics(self, metrics: Union[List[str], str, None] = None) -> None: """Enable logging for specific metrics. Args: - metrics: List of metric identifiers to enable, "all" for all registered + metrics: List of metric identifiers to enable, "all" for all registered metrics, or None to disable all metrics. """ if metrics == "all": @@ -257,21 +261,23 @@ def enable_metrics(self, metrics: Union[List[str], str, None] = None) -> None: def _enable_selected_metrics(self, metrics: Union[List[str], set]) -> None: """Enable only the selected metrics that are registered. - + Args: metrics: List or set of metric identifiers to enable. """ valid_metrics = set(metrics) & set(self._registered_metrics.keys()) invalid_metrics = set(metrics) - set(self._registered_metrics.keys()) - + if invalid_metrics: print( f"Warning: Attempting to enable unregistered metrics: {invalid_metrics}" ) - + self.enabled_metrics = valid_metrics - def log(self, identifier: str, value: Any, metadata: Optional[Dict[str, Any]] = None) -> None: + def log( + self, identifier: str, value: Any, metadata: Optional[Dict[str, Any]] = None + ) -> None: """Log a metric value with optional metadata. Location is auto-inferred from the calling context. This only works if log_path is defined. @@ -295,10 +301,10 @@ def log(self, identifier: str, value: Any, metadata: Optional[Dict[str, Any]] = def _should_log_metric(self, identifier: str) -> bool: """Check if the metric should be logged based on configuration. - + Args: identifier: Metric identifier to check. - + Returns: True if the metric should be logged, False otherwise. """ @@ -319,7 +325,7 @@ def _should_log_metric(self, identifier: str) -> bool: def _is_within_limits(self) -> bool: """Check if logging is within configured limits. - + Returns: True if within limits, False if max records reached. """ @@ -330,25 +336,22 @@ def _is_within_limits(self) -> bool: def _passes_sampling(self) -> bool: """Check if event passes sampling filter. - + Returns: True if event should be logged based on sampling factor. """ return self.sampling_factor >= 1.0 or random.random() <= self.sampling_factor def _create_log_event( - self, - identifier: str, - value: Any, - metadata: Optional[Dict[str, Any]] + self, identifier: str, value: Any, metadata: Optional[Dict[str, Any]] ) -> LogEvent: """Create a log event from the provided data. - + Args: identifier: Metric identifier. value: Metric value. metadata: Optional metadata. - + Returns: LogEvent instance ready for logging. """ @@ -362,7 +365,7 @@ def _create_log_event( def _add_event_and_flush_if_needed(self, event: LogEvent) -> None: """Add event to queue and flush if threshold is reached. - + Args: event: LogEvent to add to the queue. """ @@ -395,9 +398,11 @@ def configure_logging( self._update_logging_limits(max_records, sampling_factor) self._total_records_logged = 0 - def _update_logging_limits(self, max_records: Optional[int], sampling_factor: float) -> None: + def _update_logging_limits( + self, max_records: Optional[int], sampling_factor: float + ) -> None: """Update logging limits and sampling factor. - + Args: max_records: Maximum records limit. sampling_factor: Event sampling probability. @@ -407,7 +412,7 @@ def _update_logging_limits(self, max_records: Optional[int], sampling_factor: fl def flush(self) -> None: """Force flush the current queue to disk. - + Writes all queued events to the log file in JSONL format. """ if not self.log_queue or self.log_path is None: @@ -419,7 +424,7 @@ def flush(self) -> None: def _write_events_to_file(self, filepath: str) -> None: """Write all queued events to the specified file. - + Args: filepath: Path to the log file. """ @@ -431,10 +436,10 @@ def _write_events_to_file(self, filepath: str) -> None: def _serialize_event(self, event: LogEvent) -> Dict[str, Any]: """Serialize a log event to a dictionary. - + Args: event: LogEvent to serialize. - + Returns: Dictionary representation of the event. """ @@ -444,10 +449,10 @@ def _serialize_event(self, event: LogEvent) -> Dict[str, Any]: def is_metric_enabled(self, identifier: str) -> bool: """Check if a specific metric is enabled for logging. - + Args: identifier: Metric identifier to check. - + Returns: True if the metric is enabled, False otherwise. """ @@ -455,7 +460,7 @@ def is_metric_enabled(self, identifier: str) -> bool: def get_enabled_metrics(self) -> set: """Get currently enabled metrics. - + Returns: Set of enabled metric identifiers. """ @@ -463,7 +468,7 @@ def get_enabled_metrics(self) -> set: def is_logging_configured(self) -> bool: """Check if logging is configured. - + Returns: True if log_path is set, False otherwise. """ @@ -471,7 +476,7 @@ def is_logging_configured(self) -> bool: def get_total_records_logged(self) -> int: """Get the total number of records logged. - + Returns: Number of records logged since initialization or last configure_logging call. """ @@ -479,7 +484,7 @@ def get_total_records_logged(self) -> int: def is_max_records_reached(self) -> bool: """Check if the maximum number of records has been reached. - + Returns: True if max records limit has been reached, False otherwise. """ @@ -499,7 +504,7 @@ def get_records_remaining(self) -> Optional[int]: def get_sampling_factor(self) -> float: """Get the current sampling factor. - + Returns: Current sampling factor (0.0-1.0). """ @@ -507,7 +512,7 @@ def get_sampling_factor(self) -> float: def get_max_records(self) -> Optional[int]: """Get the current max_records limit. - + Returns: Maximum records limit, or None if no limit is set. """ diff --git a/sparse_attention_hub/plotting/generator.py b/sparse_attention_hub/plotting/generator.py index 8d4461ae..1847b134 100644 --- a/sparse_attention_hub/plotting/generator.py +++ b/sparse_attention_hub/plotting/generator.py @@ -12,17 +12,17 @@ class PlotGenerator: """Generates plots for sparse attention analysis. - + This class provides functionality to generate various types of plots for analyzing sparse attention patterns at different granularities. - + Attributes: storage_path: Directory path where generated plots will be saved. """ def __init__(self, storage_path: str = "./plots") -> None: """Initialize the PlotGenerator. - + Args: storage_path: Directory path for storing generated plots. Defaults to "./plots". @@ -57,7 +57,7 @@ def generate_plot( Returns: Absolute path to the generated plot file. - + Raises: ValueError: If the specified granularity is not supported. """ @@ -87,18 +87,18 @@ def _generate_line_plot( Path to the generated plot file. """ fig, ax = plt.subplots(figsize=(10, 6)) - + if data is None: self._plot_sample_line_data(ax, granularity) else: self._plot_actual_line_data(ax, data) - + self._configure_line_plot_axes(ax, granularity) return self._save_plot(fig, "plot", granularity, data) def _plot_sample_line_data(self, ax: plt.Axes, granularity: Granularity) -> None: """Plot sample line data for demonstration. - + Args: ax: Matplotlib axes object to plot on. granularity: Granularity level for labeling. @@ -109,7 +109,7 @@ def _plot_sample_line_data(self, ax: plt.Axes, granularity: Granularity) -> None def _plot_actual_line_data(self, ax: plt.Axes, data: Dict[str, Any]) -> None: """Plot actual line data from provided data dictionary. - + Args: ax: Matplotlib axes object to plot on. data: Data dictionary containing plot information. @@ -120,12 +120,14 @@ def _plot_actual_line_data(self, ax: plt.Axes, data: Dict[str, Any]) -> None: def _configure_line_plot_axes(self, ax: plt.Axes, granularity: Granularity) -> None: """Configure axes for line plots. - + Args: ax: Matplotlib axes object to configure. granularity: Granularity level for title formatting. """ - title = f"Sparse Attention Analysis - {granularity.value.replace('_', ' ').title()}" + title = ( + f"Sparse Attention Analysis - {granularity.value.replace('_', ' ').title()}" + ) ax.set_title(title) ax.set_xlabel("Position") ax.set_ylabel("Attention Weight") @@ -147,38 +149,36 @@ def _generate_heatmap_plot( Returns: Path to the generated plot file. - + Raises: ValueError: If data is provided but doesn't contain required attention_matrix. """ fig, ax = plt.subplots(figsize=(8, 8)) - + attention_matrix = self._get_attention_matrix(granularity, data) self._create_heatmap(ax, attention_matrix) self._configure_heatmap_axes(ax, granularity) - + return self._save_plot(fig, "heatmap", granularity, data) def _get_attention_matrix( - self, - granularity: Granularity, - data: Optional[Dict[str, Any]] + self, granularity: Granularity, data: Optional[Dict[str, Any]] ) -> np.ndarray: """Get attention matrix from data or generate sample data. - + Args: granularity: Granularity level for determining matrix size. data: Optional data dictionary containing attention matrix. - + Returns: Attention matrix as numpy array. - + Raises: ValueError: If data is provided but doesn't contain attention_matrix. """ if data is None: return self._generate_sample_attention_matrix(granularity) - + attention_matrix = data.get("attention_matrix") if attention_matrix is None: raise ValueError("attention_matrix required in data for heatmap") @@ -186,10 +186,10 @@ def _get_attention_matrix( def _generate_sample_attention_matrix(self, granularity: Granularity) -> np.ndarray: """Generate sample attention matrix for demonstration. - + Args: granularity: Granularity level for determining matrix size. - + Returns: Symmetric attention matrix. """ @@ -199,7 +199,7 @@ def _generate_sample_attention_matrix(self, granularity: Granularity) -> np.ndar def _create_heatmap(self, ax: plt.Axes, attention_matrix: np.ndarray) -> None: """Create heatmap visualization. - + Args: ax: Matplotlib axes object to plot on. attention_matrix: Attention matrix to visualize. @@ -215,7 +215,7 @@ def _create_heatmap(self, ax: plt.Axes, attention_matrix: np.ndarray) -> None: def _configure_heatmap_axes(self, ax: plt.Axes, granularity: Granularity) -> None: """Configure axes for heatmap plots. - + Args: ax: Matplotlib axes object to configure. granularity: Granularity level for title formatting. @@ -226,20 +226,20 @@ def _configure_heatmap_axes(self, ax: plt.Axes, granularity: Granularity) -> Non ax.set_ylabel("Query Position") def _save_plot( - self, - fig: plt.Figure, - plot_type: str, - granularity: Granularity, - data: Optional[Dict[str, Any]] + self, + fig: plt.Figure, + plot_type: str, + granularity: Granularity, + data: Optional[Dict[str, Any]], ) -> str: """Save plot to file and close figure. - + Args: fig: Matplotlib figure object to save. plot_type: Type of plot for filename. granularity: Granularity level for filename. data: Data used for generating unique filename hash. - + Returns: Absolute path to the saved plot file. """ @@ -250,9 +250,7 @@ def _save_plot( return filepath def generate_comparison_plot( - self, - data_dict: Dict[str, Any], - granularity: Granularity + self, data_dict: Dict[str, Any], granularity: Granularity ) -> str: """Generate comparison plot for multiple datasets. @@ -264,15 +262,15 @@ def generate_comparison_plot( Path to the generated comparison plot file. """ fig, ax = plt.subplots(figsize=(12, 8)) - + self._plot_comparison_data(ax, data_dict) self._configure_comparison_axes(ax, granularity) - + return self._save_plot(fig, "comparison", granularity, data_dict) def _plot_comparison_data(self, ax: plt.Axes, data_dict: Dict[str, Any]) -> None: """Plot comparison data for multiple datasets. - + Args: ax: Matplotlib axes object to plot on. data_dict: Dictionary mapping labels to data. @@ -282,9 +280,11 @@ def _plot_comparison_data(self, ax: plt.Axes, data_dict: Dict[str, Any]) -> None # This is a placeholder for future actual data plotting pass - def _configure_comparison_axes(self, ax: plt.Axes, granularity: Granularity) -> None: + def _configure_comparison_axes( + self, ax: plt.Axes, granularity: Granularity + ) -> None: """Configure axes for comparison plots. - + Args: ax: Matplotlib axes object to configure. granularity: Granularity level for title formatting. diff --git a/sparse_attention_hub/sparse_attention/efficient_attention/base.py b/sparse_attention_hub/sparse_attention/efficient_attention/base.py index 98fe1678..06be8e79 100644 --- a/sparse_attention_hub/sparse_attention/efficient_attention/base.py +++ b/sparse_attention_hub/sparse_attention/efficient_attention/base.py @@ -13,7 +13,7 @@ @dataclass class EfficientAttentionConfig(SparseAttentionConfig): """Configuration class for efficient attention mechanisms. - + This is a base configuration class for production-ready sparse attention implementations that prioritize efficiency and performance. """ @@ -23,7 +23,7 @@ class EfficientAttentionConfig(SparseAttentionConfig): class EfficientAttention(SparseAttention): """Abstract base class for efficient attention mechanisms. - + This class serves as the base for production-ready sparse attention implementations that are optimized for performance and memory efficiency, such as HashAttention and DoubleSparsity. @@ -79,9 +79,11 @@ def create_from_config(cls, config: SparseAttentionConfig) -> "EfficientAttentio return concrete_class.create_from_config(config) @classmethod - def _get_implementation_registry(cls) -> Dict[Type[EfficientAttentionConfig], Type["EfficientAttention"]]: + def _get_implementation_registry( + cls, + ) -> Dict[Type[EfficientAttentionConfig], Type["EfficientAttention"]]: """Get the registry mapping config types to implementation classes. - + Returns: Dictionary mapping config types to their corresponding implementation classes. """ @@ -100,19 +102,19 @@ def _get_implementation_registry(cls) -> Dict[Type[EfficientAttentionConfig], Ty @classmethod def _get_concrete_class( - cls, + cls, config: EfficientAttentionConfig, - registry: Dict[Type[EfficientAttentionConfig], Type["EfficientAttention"]] + registry: Dict[Type[EfficientAttentionConfig], Type["EfficientAttention"]], ) -> Type["EfficientAttention"]: """Get the concrete implementation class for the given configuration. - + Args: config: Configuration instance. registry: Registry mapping config types to implementation classes. - + Returns: Concrete implementation class. - + Raises: ValueError: If no implementation is found for the config type. """ diff --git a/sparse_attention_hub/sparse_attention/research_attention/base.py b/sparse_attention_hub/sparse_attention/research_attention/base.py index 12e96149..0fed826a 100644 --- a/sparse_attention_hub/sparse_attention/research_attention/base.py +++ b/sparse_attention_hub/sparse_attention/research_attention/base.py @@ -24,10 +24,10 @@ @dataclass class ResearchAttentionConfig(SparseAttentionConfig): """Configuration class for research attention mechanisms. - + This configuration specifies the masker components that will be applied sequentially to create sparse attention patterns for research purposes. - + Attributes: masker_configs: List of masker configurations to apply in sequence. """ @@ -37,11 +37,11 @@ class ResearchAttentionConfig(SparseAttentionConfig): class ResearchAttention(SparseAttention): """Base class for research attention mechanisms with configurable maskers. - + This class implements sparse attention by applying a sequence of maskers to create custom attention patterns. It supports metrics logging and validation of masker configurations. - + Attributes: maskers: List of research maskers to apply sequentially. """ @@ -68,10 +68,10 @@ def __init__( def _validate_masker_configuration(self, maskers: List[ResearchMasker]) -> None: """Validate the masker configuration. - + Args: maskers: List of maskers to validate. - + Raises: ValueError: If more than one sampling masker is provided. """ @@ -124,9 +124,9 @@ def custom_attention( sparse_meta_data=sparse_meta_data, **kwargs, ) - + self._log_attention_density(sparse_attention_mask, kwargs) - + attention_output, attention_weights = self._compute_masked_attention( module=module, queries=queries, @@ -138,7 +138,7 @@ def custom_attention( sparse_attention_mask=sparse_attention_mask, **kwargs, ) - + self._log_attention_error( module=module, queries=queries, @@ -155,11 +155,11 @@ def custom_attention( def _create_initial_mask(self, queries: torch.Tensor, keys: torch.Tensor) -> Mask: """Create an initial empty mask for the attention computation. - + Args: queries: Query tensor. keys: Key tensor. - + Returns: Empty mask with appropriate shape. """ @@ -184,7 +184,7 @@ def _apply_maskers( **kwargs: Dict[str, Any], ) -> Mask: """Apply all maskers sequentially to create the final sparse attention mask. - + Args: sparse_attention_mask: Initial mask to start with. keys: Key tensor. @@ -195,7 +195,7 @@ def _apply_maskers( dropout: Dropout probability. sparse_meta_data: Additional metadata. **kwargs: Additional keyword arguments. - + Returns: Final sparse attention mask after applying all maskers. """ @@ -213,9 +213,11 @@ def _apply_maskers( ) return sparse_attention_mask - def _log_attention_density(self, sparse_attention_mask: Mask, kwargs: Dict[str, Any]) -> None: + def _log_attention_density( + self, sparse_attention_mask: Mask, kwargs: Dict[str, Any] + ) -> None: """Log attention density metric if enabled. - + Args: sparse_attention_mask: The sparse attention mask. kwargs: Keyword arguments containing layer information. @@ -240,7 +242,7 @@ def _compute_masked_attention( **kwargs: Dict[str, Any], ) -> Tuple[torch.Tensor, torch.Tensor]: """Compute the masked attention output and weights. - + Args: module: The attention module. queries: Query tensor. @@ -251,7 +253,7 @@ def _compute_masked_attention( dropout: Dropout probability. sparse_attention_mask: Sparse attention mask. **kwargs: Additional keyword arguments. - + Returns: Tuple of attention output and attention weights. """ @@ -281,7 +283,7 @@ def _log_attention_error( **kwargs: Dict[str, Any], ) -> None: """Log attention output error metric if enabled. - + Args: module: The attention module. queries: Query tensor. @@ -334,12 +336,14 @@ def create_from_config(cls, config: SparseAttentionConfig) -> "ResearchAttention return cls(config, maskers) @classmethod - def _create_maskers_from_config(cls, masker_configs: List[MaskerConfig]) -> List[ResearchMasker]: + def _create_maskers_from_config( + cls, masker_configs: List[MaskerConfig] + ) -> List[ResearchMasker]: """Create research masker objects from their configurations. - + Args: masker_configs: List of masker configurations. - + Returns: List of configured research masker instances. """ diff --git a/sparse_attention_hub/sparse_attention/research_attention/maskers/sampling/implementations/random_sampling.py b/sparse_attention_hub/sparse_attention/research_attention/maskers/sampling/implementations/random_sampling.py index ed72b255..a5b06044 100644 --- a/sparse_attention_hub/sparse_attention/research_attention/maskers/sampling/implementations/random_sampling.py +++ b/sparse_attention_hub/sparse_attention/research_attention/maskers/sampling/implementations/random_sampling.py @@ -37,7 +37,9 @@ class RandomSamplingMaskerConfig(SamplingMaskerConfig): no indices are sampled, while 1.0 means all indices are sampled. """ - sampling_rate: float # Float in range [0,1] representing fraction of indices to sample + sampling_rate: ( + float # Float in range [0,1] representing fraction of indices to sample + ) def __post_init__(self) -> None: """Validate sampling_rate after initialization.""" diff --git a/sparse_attention_hub/sparse_attention/utils/hashattention_utils.py b/sparse_attention_hub/sparse_attention/utils/hashattention_utils.py index d99eabeb..ad30c215 100644 --- a/sparse_attention_hub/sparse_attention/utils/hashattention_utils.py +++ b/sparse_attention_hub/sparse_attention/utils/hashattention_utils.py @@ -57,13 +57,13 @@ def _convert_layer_weights( num_mlp_layers: int, ) -> Dict[str, List[torch.Tensor]]: """Convert weights for a single layer. - + Args: usa_state_dict: USA checkpoint state dictionary. layer_idx: Index of the layer to process. num_heads: Number of attention heads. num_mlp_layers: Number of MLP layers. - + Returns: Dictionary containing converted weights for the layer. """ @@ -116,7 +116,7 @@ def _extract_head_weights( key_biases_per_layer: List[List[torch.Tensor]], ) -> None: """Extract weights for a single attention head. - + Args: usa_state_dict: USA checkpoint state dictionary. layer_idx: Index of the current layer. @@ -132,15 +132,23 @@ def _extract_head_weights( # Extract weights from MLP layers (linear layers at indices 0, 2, 4, ...) linear_indices = [i * 2 for i in range(num_mlp_layers)] - + for i, linear_idx in enumerate(linear_indices): _extract_query_weights( - usa_state_dict, query_prefix, linear_idx, i, - query_matrices_per_layer, query_biases_per_layer + usa_state_dict, + query_prefix, + linear_idx, + i, + query_matrices_per_layer, + query_biases_per_layer, ) _extract_key_weights( - usa_state_dict, key_prefix, linear_idx, i, - key_matrices_per_layer, key_biases_per_layer + usa_state_dict, + key_prefix, + linear_idx, + i, + key_matrices_per_layer, + key_biases_per_layer, ) @@ -153,7 +161,7 @@ def _extract_query_weights( query_biases_per_layer: List[List[torch.Tensor]], ) -> None: """Extract query weights for a specific MLP layer. - + Args: usa_state_dict: USA checkpoint state dictionary. query_prefix: Prefix for query weight keys. @@ -187,7 +195,7 @@ def _extract_key_weights( key_biases_per_layer: List[List[torch.Tensor]], ) -> None: """Extract key weights for a specific MLP layer. - + Args: usa_state_dict: USA checkpoint state dictionary. key_prefix: Prefix for key weight keys. @@ -221,7 +229,7 @@ def _stack_head_weights( key_biases_per_layer: List[List[torch.Tensor]], ) -> None: """Stack weights from all heads for each MLP layer. - + Args: layer_weights: Dictionary to store the stacked weights. num_mlp_layers: Number of MLP layers. @@ -235,15 +243,9 @@ def _stack_head_weights( layer_weights["query_matrix"].append( torch.stack(query_matrices_per_layer[i]) ) - layer_weights["query_bias"].append( - torch.stack(query_biases_per_layer[i]) - ) - layer_weights["key_matrix"].append( - torch.stack(key_matrices_per_layer[i]) - ) - layer_weights["key_bias"].append( - torch.stack(key_biases_per_layer[i]) - ) + layer_weights["query_bias"].append(torch.stack(query_biases_per_layer[i])) + layer_weights["key_matrix"].append(torch.stack(key_matrices_per_layer[i])) + layer_weights["key_bias"].append(torch.stack(key_biases_per_layer[i])) def create_hat_weights_file_from_usa( @@ -282,11 +284,10 @@ def create_hat_weights_file_from_usa( def _save_weights_to_file( - hat_weights: Dict[int, Dict[str, List[torch.Tensor]]], - target_path: str + hat_weights: Dict[int, Dict[str, List[torch.Tensor]]], target_path: str ) -> None: """Save HashAttention weights to a pickle file. - + Args: hat_weights: Dictionary of HashAttention weights to save. target_path: Path where the weights file will be saved. @@ -322,10 +323,10 @@ def load_hat_weights( def _load_weights_from_file(file_path: str) -> Dict[int, Dict[str, List[torch.Tensor]]]: """Load weights from a pickle file. - + Args: file_path: Path to the pickle file. - + Returns: Dictionary of loaded weights. """ @@ -334,11 +335,10 @@ def _load_weights_from_file(file_path: str) -> Dict[int, Dict[str, List[torch.Te def _move_weights_to_device( - hat_weights: Dict[int, Dict[str, List[torch.Tensor]]], - device: str + hat_weights: Dict[int, Dict[str, List[torch.Tensor]]], device: str ) -> None: """Move all weights to the specified device. - + Args: hat_weights: Dictionary of HashAttention weights to move. device: Target device for the weights. diff --git a/sparse_attention_hub/sparse_attention/utils/kv_utils.py b/sparse_attention_hub/sparse_attention/utils/kv_utils.py index afc52d46..81f41def 100644 --- a/sparse_attention_hub/sparse_attention/utils/kv_utils.py +++ b/sparse_attention_hub/sparse_attention/utils/kv_utils.py @@ -1,4 +1,5 @@ """ Utility functions for common kv manipulation. """ + import torch diff --git a/tests/integration/test_adapter_integration.py b/tests/integration/test_adapter_integration.py index 0e88542d..b5dc85a4 100644 --- a/tests/integration/test_adapter_integration.py +++ b/tests/integration/test_adapter_integration.py @@ -48,14 +48,18 @@ class TestAdapterIntegration: def setup_method(self) -> None: """Set up test fixtures - reset ModelServer singleton.""" from sparse_attention_hub.adapters.model_servers.base import ModelServer + ModelServer._instance = None def teardown_method(self) -> None: """Clean up after each test - reset ModelServer singleton.""" from sparse_attention_hub.adapters.model_servers.base import ModelServer + ModelServer._instance = None - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_full_request_processing_flow( self, mock_tokenizer, mock_model, sparse_attention_config @@ -141,7 +145,9 @@ def test_full_request_processing_flow( assert mock_tokenizer_instance.encode.call_count == 2 mock_tokenizer_instance.decode.assert_called_once() - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_multiple_questions_processing( self, mock_tokenizer, mock_model, sparse_attention_config @@ -246,7 +252,9 @@ def test_multiple_questions_processing( assert mock_tokenizer_instance.encode.call_count == 3 assert mock_tokenizer_instance.decode.call_count == 2 - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_mode_switching_integration( self, mock_tokenizer, mock_model, sparse_attention_config @@ -287,7 +295,9 @@ def test_mode_switching_integration( # Should not raise any errors pass - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_custom_attention_function_integration( self, mock_tokenizer, mock_model, sparse_attention_config @@ -350,7 +360,9 @@ def test_custom_attention_function_integration( mock_custom_attention.assert_called_once() assert result is not None - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_error_handling_integration( self, mock_tokenizer, mock_model, sparse_attention_config @@ -399,7 +411,9 @@ def test_error_handling_integration( # missing sparse_meta_data ) - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_adapter_with_device_configuration( self, mock_tokenizer, mock_model, sparse_attention_config @@ -453,7 +467,9 @@ def test_adapter_with_device_configuration( "test-model", device_map="cuda", torch_dtype=torch.float16 ) - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_adapter_cleanup_on_exception( self, mock_tokenizer, mock_model, sparse_attention_config diff --git a/tests/integration/test_benchmark.py b/tests/integration/test_benchmark.py index c67b75a3..0c2807d1 100644 --- a/tests/integration/test_benchmark.py +++ b/tests/integration/test_benchmark.py @@ -50,7 +50,9 @@ def sparse_attention_config(masker_config): class TestBenchmarkAdapterIntegration: """Test benchmark integration with real adapter interfaces.""" - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_benchmark_with_real_adapter_interface( self, @@ -118,7 +120,9 @@ def mock_process_request( assert (result_path / "raw_results.csv").exists() assert (result_path / "metrics.json").exists() - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_dense_only_adapter_integration( self, mock_tokenizer_class, mock_model_class, temp_result_dir @@ -382,6 +386,7 @@ class TestErrorHandlingIntegration: def test_adapter_failure_recovery(self, temp_result_dir): """Test benchmark recovery when adapter fails intermittently.""" + # Create adapter that fails on certain contexts def failing_process_request( request: Request, diff --git a/tests/unit/adapters/model_servers/test_huggingface.py b/tests/unit/adapters/model_servers/test_huggingface.py index 5ea48060..256d32c0 100644 --- a/tests/unit/adapters/model_servers/test_huggingface.py +++ b/tests/unit/adapters/model_servers/test_huggingface.py @@ -485,8 +485,10 @@ def test_validate_gpu_availability_success( mock_cuda_available.return_value = True mock_device_count.return_value = 4 - with patch("torch.cuda.device"), patch("torch.zeros") as mock_zeros, patch( - "torch.cuda.empty_cache" + with ( + patch("torch.cuda.device"), + patch("torch.zeros") as mock_zeros, + patch("torch.cuda.empty_cache"), ): mock_zeros.return_value = Mock() result = self.server.validate_gpu_availability(0) diff --git a/tests/unit/adapters/test_adapters.py b/tests/unit/adapters/test_adapters.py index 60b36b0d..78c07509 100644 --- a/tests/unit/adapters/test_adapters.py +++ b/tests/unit/adapters/test_adapters.py @@ -20,6 +20,7 @@ ) from sparse_attention_hub.adapters.model_servers.base import ModelServer + @pytest.mark.unit class TestRequest: """Test the Request class.""" @@ -147,12 +148,14 @@ def setup_method(self) -> None: masker_configs=[self.masker_config] ) ModelServer._instance = None - + def teardown_method(self) -> None: """Clean up after each test.""" ModelServer._instance = None - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_create_model(self, mock_tokenizer, mock_model) -> None: """Test model creation.""" @@ -186,7 +189,9 @@ def test_create_model(self, mock_tokenizer, mock_model) -> None: "test-model", torch_dtype=torch.float16 ) - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_create_model_with_torch_dtype(self, mock_tokenizer, mock_model) -> None: """Test model creation with torch_dtype parameter.""" @@ -217,7 +222,9 @@ def test_create_model_with_torch_dtype(self, mock_tokenizer, mock_model) -> None # Check that adapter was created successfully assert adapter is not None - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_create_model_with_existing_pad_token( self, mock_tokenizer, mock_model @@ -243,7 +250,9 @@ def test_create_model_with_existing_pad_token( # Check that pad_token was not changed assert adapter.tokenizer.pad_token == "" - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_get_custom_attention_function(self, mock_tokenizer, mock_model) -> None: """Test get_custom_attention_function returns a callable.""" @@ -265,7 +274,9 @@ def test_get_custom_attention_function(self, mock_tokenizer, mock_model) -> None custom_fn = adapter.get_custom_attention_function(adapter.sparse_attention) assert callable(custom_fn) - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_generate_unique_attention_name(self, mock_tokenizer, mock_model) -> None: """Test unique attention name generation.""" @@ -290,7 +301,9 @@ def test_generate_unique_attention_name(self, mock_tokenizer, mock_model) -> Non assert name2.startswith("sparse_attention_") assert name1 != name2 # Should be unique - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_enable_sparse_mode_when_not_available( self, mock_tokenizer, mock_model @@ -317,7 +330,9 @@ def test_enable_sparse_mode_when_not_available( exc_info.value ) - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_enable_sparse_and_dense_modes(self, mock_tokenizer, mock_model) -> None: """Test enable_sparse_mode and enable_dense_mode context managers.""" @@ -352,7 +367,9 @@ def test_enable_sparse_and_dense_modes(self, mock_tokenizer, mock_model) -> None assert first_name == second_name - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_inheritance(self, mock_tokenizer, mock_model) -> None: """Test that ModelAdapterHF properly inherits from ModelAdapter.""" @@ -372,7 +389,9 @@ def test_inheritance(self, mock_tokenizer, mock_model) -> None: assert isinstance(adapter, ModelHubAdapterInterface) assert isinstance(adapter, SparseAttentionAdapterInterface) - @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM") + @patch( + "sparse_attention_hub.adapters.model_servers.huggingface.AutoModelForCausalLM" + ) @patch("sparse_attention_hub.adapters.model_servers.huggingface.AutoTokenizer") def test_adapter_properties(self, mock_tokenizer, mock_model) -> None: """Test adapter properties are set correctly.""" diff --git a/tests/unit/benchmark/test_longbench.py b/tests/unit/benchmark/test_longbench.py index 3ff12940..2810ec00 100644 --- a/tests/unit/benchmark/test_longbench.py +++ b/tests/unit/benchmark/test_longbench.py @@ -314,7 +314,7 @@ def test_longbench_post_run_evaluate_missing_length_column(self): "task": ["qasper_e"], "predicted_answer": ["Answer 1"], "answers": [["Truth 1"]], - "all_classes": [[]] + "all_classes": [[]], # Missing 'length' column } ) diff --git a/tests/unit/sparse_attention/research_attention/maskers/fixed/implementations/test_hashattention_top_k.py b/tests/unit/sparse_attention/research_attention/maskers/fixed/implementations/test_hashattention_top_k.py index 680c6090..acc49ed1 100644 --- a/tests/unit/sparse_attention/research_attention/maskers/fixed/implementations/test_hashattention_top_k.py +++ b/tests/unit/sparse_attention/research_attention/maskers/fixed/implementations/test_hashattention_top_k.py @@ -5,6 +5,7 @@ :date: 2025-06-29 :summary: Tests for HashAttentionTopKMasker implementation. """ + import os import pickle import tempfile diff --git a/tests/unit/sparse_attention/test_configs_and_factories.py b/tests/unit/sparse_attention/test_configs_and_factories.py index 095ed934..040730ae 100644 --- a/tests/unit/sparse_attention/test_configs_and_factories.py +++ b/tests/unit/sparse_attention/test_configs_and_factories.py @@ -1,4 +1,5 @@ """Tests for sparse attention config classes and create_from_config methods.""" + import pytest diff --git a/tests/unit/sparse_attention/utils/test_mask_attention_utils.py b/tests/unit/sparse_attention/utils/test_mask_attention_utils.py index 9ef1b93d..13b1756a 100644 --- a/tests/unit/sparse_attention/utils/test_mask_attention_utils.py +++ b/tests/unit/sparse_attention/utils/test_mask_attention_utils.py @@ -6,7 +6,6 @@ :summary: Tests for sparse attention. This file is part of the Sparse Attention Hub project. """ - import mock import numpy as np import pytest diff --git a/tutorials/py_examples/02_streaming_llm_demo_hf.py b/tutorials/py_examples/02_streaming_llm_demo_hf.py index dfcbb084..afa4c7ee 100644 --- a/tutorials/py_examples/02_streaming_llm_demo_hf.py +++ b/tutorials/py_examples/02_streaming_llm_demo_hf.py @@ -1,31 +1,35 @@ #!/usr/bin/env python3 -''' +""" You can also choose to have more control instead calling process_request directly. -''' +""" import torch from transformers import AutoTokenizer, AutoModelForCausalLM import time -from sparse_attention_hub.sparse_attention.research_attention import ResearchAttentionConfig +from sparse_attention_hub.sparse_attention.research_attention import ( + ResearchAttentionConfig, +) from sparse_attention_hub.sparse_attention.research_attention.maskers.fixed.implementations import ( - LocalMaskerConfig, SinkMaskerConfig + LocalMaskerConfig, + SinkMaskerConfig, ) from sparse_attention_hub.adapters.huggingface import ModelAdapterHF -device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') +device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model_name = "meta-llama/Llama-3.1-8B-Instruct" -#D model_name = "microsoft/DialoGPT-medium" -#D model_name = "google/gemma-3n-E4B-it" +# D model_name = "microsoft/DialoGPT-medium" +# D model_name = "google/gemma-3n-E4B-it" model_name = "microsoft/Phi-4-mini-instruct" model_name = "mistralai/Mistral-7B-Instruct-v0.3" model_name = "deepseek-ai/DeepSeek-R1-0528-Qwen3-8B" import os -os.chdir('/data/apdesai/code/sparse-attention-hub') -device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') +os.chdir("/data/apdesai/code/sparse-attention-hub") + +device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print(f"Device: {device}") # Create StreamingLLM configuration: Sink (4 tokens) + Local (64 tokens) sink_config = SinkMaskerConfig(sink_size=4) @@ -34,10 +38,12 @@ print(f"โœ… StreamingLLM config: Sink(4) + Local(64)") -adapter = ModelAdapterHF(model_name="meta-llama/Llama-3.1-8B-Instruct", - sparse_attention_config=research_config, - model_kwargs={"torch_dtype": torch.bfloat16}, - device="cuda:0") +adapter = ModelAdapterHF( + model_name="meta-llama/Llama-3.1-8B-Instruct", + sparse_attention_config=research_config, + model_kwargs={"torch_dtype": torch.bfloat16}, + device="cuda:0", +) test_content = """ @@ -51,11 +57,13 @@ print("Running Full Attention") -messages = [ - {"role": "user", "content": test_content} -] -test_content = adapter.tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) -input_ids = adapter.tokenizer.encode(test_content, return_tensors="pt", add_special_tokens=False).to(device) +messages = [{"role": "user", "content": test_content}] +test_content = adapter.tokenizer.apply_chat_template( + messages, tokenize=False, add_generation_prompt=True +) +input_ids = adapter.tokenizer.encode( + test_content, return_tensors="pt", add_special_tokens=False +).to(device) output_ids = adapter.model.generate(input_ids, max_new_tokens=50, do_sample=False) @@ -66,10 +74,10 @@ with adapter.enable_sparse_mode(): - output_ids = adapter.model.generate(input_ids, max_new_tokens=50, do_sample=False, sparse_meta_data={}) + output_ids = adapter.model.generate( + input_ids, max_new_tokens=50, do_sample=False, sparse_meta_data={} + ) # model.generate() validates kwargs and will not let sparse_meta_data to be passed in which is required # Locally, I removed the validation for this to work. TODO(we can write our own generate function for utility) output_text = adapter.tokenizer.decode(output_ids[0], skip_special_tokens=True) print("Streaming Attention Response: ", output_text) - - diff --git a/tutorials/py_examples/02_streaming_llm_tutorial.py b/tutorials/py_examples/02_streaming_llm_tutorial.py index 3e95ae57..aee56ebf 100644 --- a/tutorials/py_examples/02_streaming_llm_tutorial.py +++ b/tutorials/py_examples/02_streaming_llm_tutorial.py @@ -1,17 +1,21 @@ import os -os.chdir('/data/apdesai/code/sparse-attention-hub') + +os.chdir("/data/apdesai/code/sparse-attention-hub") import torch from transformers import AutoTokenizer, AutoModelForCausalLM import time -from sparse_attention_hub.sparse_attention.research_attention import ResearchAttentionConfig +from sparse_attention_hub.sparse_attention.research_attention import ( + ResearchAttentionConfig, +) from sparse_attention_hub.sparse_attention.research_attention.maskers.fixed.implementations import ( - LocalMaskerConfig, SinkMaskerConfig + LocalMaskerConfig, + SinkMaskerConfig, ) from sparse_attention_hub.adapters.huggingface import ModelAdapterHF -device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') +device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print(f"Device: {device}") sink_config = SinkMaskerConfig(sink_size=4) @@ -25,10 +29,12 @@ # model_name = "deepseek-ai/DeepSeek-R1-0528-Qwen3-8B" model_name = "meta-llama/Llama-3.1-8B-Instruct" -adapter = ModelAdapterHF(model_name=model_name, - sparse_attention_config=research_config, - model_kwargs={"torch_dtype": torch.bfloat16, "device_map": "cuda"}, - device="cuda") +adapter = ModelAdapterHF( + model_name=model_name, + sparse_attention_config=research_config, + model_kwargs={"torch_dtype": torch.bfloat16, "device_map": "cuda"}, + device="cuda", +) from sparse_attention_hub.adapters import Request @@ -41,18 +47,16 @@ This approach maintains performance while reducing computational costs for long sequences. """ test_questions = [ - "Summarize the above in a single title with less than 10 words. Given only the title.", - "What are other attention mechanisms that are used in the field of LLMs?" + "Summarize the above in a single title with less than 10 words. Given only the title.", + "What are other attention mechanisms that are used in the field of LLMs?", ] request = Request( context=test_context, questions=test_questions, - ) +) print("Running Streaming Attention on Question") -response=adapter.process_request(request) -response_text=response.responses +response = adapter.process_request(request) +response_text = response.responses print("Streaming Attention Response: ", response_text) - - diff --git a/tutorials/py_examples/03_hashattention_demo.py b/tutorials/py_examples/03_hashattention_demo.py index 33bec796..0985c213 100644 --- a/tutorials/py_examples/03_hashattention_demo.py +++ b/tutorials/py_examples/03_hashattention_demo.py @@ -12,96 +12,117 @@ from typing import Dict, List from transformers import AutoTokenizer, AutoModelForCausalLM -from sparse_attention_hub.sparse_attention.research_attention import ResearchAttentionConfig +from sparse_attention_hub.sparse_attention.research_attention import ( + ResearchAttentionConfig, +) from sparse_attention_hub.sparse_attention.research_attention.maskers.fixed.implementations import ( - LocalMaskerConfig, SinkMaskerConfig, HashAttentionTopKMaskerConfig + LocalMaskerConfig, + SinkMaskerConfig, + HashAttentionTopKMaskerConfig, ) from sparse_attention_hub.adapters import ModelAdapterHF from sparse_attention_hub.adapters import Request + def convert_usa_weights_to_hash_attention( - usa_checkpoint_path: str, - num_layers: int = 32, + usa_checkpoint_path: str, + num_layers: int = 32, num_heads: int = 32, - device: str = 'cpu' + device: str = "cpu", ) -> Dict[int, Dict[str, List[torch.Tensor]]]: """Convert USA module weights to HashAttentionTopKMasker format.""" - + print(f"Loading USA weights from {usa_checkpoint_path}") usa_state_dict = torch.load(usa_checkpoint_path, map_location=device) - + hat_weights = {} - + for layer_idx in range(num_layers): layer_weights = { "query_matrix": [], "query_bias": [], "key_matrix": [], - "key_bias": [] + "key_bias": [], } - + # Collect weights for all heads in this layer query_matrices_per_layer = [[] for _ in range(3)] # 3 linear layers query_biases_per_layer = [[] for _ in range(3)] key_matrices_per_layer = [[] for _ in range(3)] key_biases_per_layer = [[] for _ in range(3)] - + for head_idx in range(num_heads): query_prefix = f"{layer_idx}.learning_to_hash_transformation_q.{head_idx}" key_prefix = f"{layer_idx}.learning_to_hash_transformation_k.{head_idx}" - + # Extract weights from 3-layer MLP (linear layers at indices 0, 2, 4) for i, linear_idx in enumerate([0, 2, 4]): # Query weights weight_key = f"{query_prefix}.{linear_idx}.weight" bias_key = f"{query_prefix}.{linear_idx}.bias" - + if weight_key in usa_state_dict: - weight = usa_state_dict[weight_key].t() # Transpose to (in_features, out_features) + weight = usa_state_dict[ + weight_key + ].t() # Transpose to (in_features, out_features) query_matrices_per_layer[i].append(weight) - + if bias_key in usa_state_dict: query_biases_per_layer[i].append(usa_state_dict[bias_key]) else: - query_biases_per_layer[i].append(torch.zeros(usa_state_dict[weight_key].shape[0])) - + query_biases_per_layer[i].append( + torch.zeros(usa_state_dict[weight_key].shape[0]) + ) + # Key weights weight_key = f"{key_prefix}.{linear_idx}.weight" bias_key = f"{key_prefix}.{linear_idx}.bias" - + if weight_key in usa_state_dict: - weight = usa_state_dict[weight_key].t() # Transpose to (in_features, out_features) + weight = usa_state_dict[ + weight_key + ].t() # Transpose to (in_features, out_features) key_matrices_per_layer[i].append(weight) - + if bias_key in usa_state_dict: key_biases_per_layer[i].append(usa_state_dict[bias_key]) else: - key_biases_per_layer[i].append(torch.zeros(usa_state_dict[weight_key].shape[0])) - + key_biases_per_layer[i].append( + torch.zeros(usa_state_dict[weight_key].shape[0]) + ) + # Stack all heads for each layer for i in range(3): if query_matrices_per_layer[i]: - layer_weights["query_matrix"].append(torch.stack(query_matrices_per_layer[i])) - layer_weights["query_bias"].append(torch.stack(query_biases_per_layer[i])) - layer_weights["key_matrix"].append(torch.stack(key_matrices_per_layer[i])) + layer_weights["query_matrix"].append( + torch.stack(query_matrices_per_layer[i]) + ) + layer_weights["query_bias"].append( + torch.stack(query_biases_per_layer[i]) + ) + layer_weights["key_matrix"].append( + torch.stack(key_matrices_per_layer[i]) + ) layer_weights["key_bias"].append(torch.stack(key_biases_per_layer[i])) - + hat_weights[layer_idx] = layer_weights - + print(f"โœ… Converted weights for {num_layers} layers, {num_heads} heads") return hat_weights -def create_dummy_weights(num_layers: int = 32, num_heads: int = 32) -> Dict[int, Dict[str, List[torch.Tensor]]]: +def create_dummy_weights( + num_layers: int = 32, num_heads: int = 32 +) -> Dict[int, Dict[str, List[torch.Tensor]]]: """Create dummy weights for demonstration purposes.""" - + hat_weights = {} for layer_idx in range(num_layers): hat_weights[layer_idx] = { "query_matrix": [ torch.randn(num_heads, 128, 128), # First linear layer torch.randn(num_heads, 128, 128), # Second linear layer - torch.randn(num_heads, 128, 32), # Third linear layer + torch.randn(num_heads, 128, 32), # Third linear layer ], "query_bias": [ torch.randn(num_heads, 128), @@ -124,20 +145,24 @@ def create_dummy_weights(num_layers: int = 32, num_heads: int = 32) -> Dict[int, def main(): """Main function demonstrating HashAttention.""" - + print("๐Ÿš€ HashAttention Example") print("=" * 50) - + # Setup - device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print(f"Device: {device}") - + # Load weights - usa_checkpoint_path = "/home/apd10/HashAttention-1.0/artifacts/llama3.1-8b-patch.64K.v1.pt" - + usa_checkpoint_path = ( + "/home/apd10/HashAttention-1.0/artifacts/llama3.1-8b-patch.64K.v1.pt" + ) + if os.path.exists(usa_checkpoint_path): try: - hat_weights = convert_usa_weights_to_hash_attention(usa_checkpoint_path, device=device) + hat_weights = convert_usa_weights_to_hash_attention( + usa_checkpoint_path, device=device + ) print("โœ… Successfully loaded USA weights") except Exception as e: print(f"โŒ Error loading USA weights: {e}") @@ -147,7 +172,7 @@ def main(): print(f"โŒ USA checkpoint not found at {usa_checkpoint_path}") print("Creating dummy weights for demonstration...") hat_weights = create_dummy_weights() - + # Configure HashAttention local_config = LocalMaskerConfig(window_size=4) sink_config = SinkMaskerConfig(sink_size=4) @@ -157,22 +182,24 @@ def main(): hat_mlp_layers=3, hat_mlp_hidden_size=128, hat_mlp_activation="silu", - hat_weights=hat_weights + hat_weights=hat_weights, ) - + research_config = ResearchAttentionConfig( masker_configs=[local_config, sink_config, hash_config] ) - + print("โœ… HashAttention config: Local(4) + Sink(4) + Hash(12 bits, 32 heavy)") - + # Load model model_name = "meta-llama/Llama-3.1-8B-Instruct" - - adapter = ModelAdapterHF(model_name=model_name, - sparse_attention_config=research_config, - model_kwargs={"torch_dtype": torch.bfloat16, "device_map": "cuda"}, - device="cuda") + + adapter = ModelAdapterHF( + model_name=model_name, + sparse_attention_config=research_config, + model_kwargs={"torch_dtype": torch.bfloat16, "device_map": "cuda"}, + device="cuda", + ) # Prepare test input test_context = """ The concept of attention mechanisms has revolutionized natural language processing and machine learning. @@ -182,8 +209,8 @@ def main(): This approach maintains performance while reducing computational costs for long sequences. """ test_questions = [ - "Summarize the above in a single title with less than 10 words. Given only the title.", - "What are other attention mechanisms that are used in the field of LLMs?" + "Summarize the above in a single title with less than 10 words. Given only the title.", + "What are other attention mechanisms that are used in the field of LLMs?", ] request = Request( @@ -192,12 +219,12 @@ def main(): ) print("Running Hash Attention on Question") - response=adapter.process_request(request, generation_kwargs={"max_new_tokens": 50}, request_kwargs={}) - response_text=response.responses + response = adapter.process_request( + request, generation_kwargs={"max_new_tokens": 50}, request_kwargs={} + ) + response_text = response.responses print("Hash Attention Response: ", response_text) - - if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/tutorials/py_examples/04_simple_benchmark_example.py b/tutorials/py_examples/04_simple_benchmark_example.py index 30b55c07..c0a2d28c 100644 --- a/tutorials/py_examples/04_simple_benchmark_example.py +++ b/tutorials/py_examples/04_simple_benchmark_example.py @@ -22,12 +22,16 @@ # Ensure we're in the correct directory and add to Python path import sys -os.chdir('/data/apdesai/code/sparse-attention-hub') -sys.path.insert(0, '/data/apdesai/code/sparse-attention-hub') -from sparse_attention_hub.sparse_attention.research_attention import ResearchAttentionConfig +os.chdir("/data/apdesai/code/sparse-attention-hub") +sys.path.insert(0, "/data/apdesai/code/sparse-attention-hub") + +from sparse_attention_hub.sparse_attention.research_attention import ( + ResearchAttentionConfig, +) from sparse_attention_hub.sparse_attention.research_attention.maskers.fixed.implementations import ( - LocalMaskerConfig, SinkMaskerConfig + LocalMaskerConfig, + SinkMaskerConfig, ) from sparse_attention_hub.adapters.huggingface import ModelAdapterHF from benchmark import MockBenchmark @@ -35,85 +39,88 @@ def main(): """Run a simple benchmark comparison between dense and sparse attention.""" - + print("๐ŸŽฏ Simple Benchmark Example") print("=" * 40) - + # Configuration model_name = "microsoft/Phi-4-mini-instruct" # Small model for quick testing - device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') - + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + print(f"Model: {model_name}") print(f"Device: {device}") - + # Create StreamingLLM configuration: Sink (4 tokens) + Local (32 tokens) sink_config = SinkMaskerConfig(sink_size=4) local_config = LocalMaskerConfig(window_size=32) - streaming_config = ResearchAttentionConfig(masker_configs=[sink_config, local_config]) - + streaming_config = ResearchAttentionConfig( + masker_configs=[sink_config, local_config] + ) + print("StreamingLLM Config: Sink(4) + Local(32)") - + # Common model arguments model_kwargs = { "model_kwargs": {"torch_dtype": torch.bfloat16}, - "device": str(device) + "device": str(device), } - + # Initialize adapters print("\n๐Ÿ”ง Loading models...") - + # Sparse adapter (StreamingLLM) print(" โœ“ Loading sparse attention model...") sparse_adapter = ModelAdapterHF( - model_name=model_name, - sparse_attention_config=streaming_config, - **model_kwargs + model_name=model_name, sparse_attention_config=streaming_config, **model_kwargs ) - + # Create mock benchmark - fast and simple mock_benchmark = MockBenchmark() - + print(f"\n๐Ÿ“Š Running MockBenchmark:") print(f" - 5 simple reading comprehension samples") print(f" - 3 different contexts (science, history, geography)") print(f" - Context sharing to test grouping efficiency") - + # Create result directories result_dir = Path("./simple_benchmark_results") result_dir.mkdir(exist_ok=True) - + sparse_dir = result_dir / "sparse" sparse_dir.mkdir(exist_ok=True) - + print("\n๐Ÿงช Running Sparse Attention Benchmark...") start_time = time.time() - + # Show dataset overview dataset_df = mock_benchmark._load_datasets() - print(f" Processing {len(dataset_df)} samples across {dataset_df['context'].nunique()} contexts...") - + print( + f" Processing {len(dataset_df)} samples across {dataset_df['context'].nunique()} contexts..." + ) + # Run sparse benchmark with sparse_adapter.enable_sparse_mode(): sparse_metrics = mock_benchmark.run_benchmark( - adapter=sparse_adapter, - result_dir=str(sparse_dir) + adapter=sparse_adapter, result_dir=str(sparse_dir) ) - + sparse_time = time.time() - start_time print(f" โœ… Sparse completed in {sparse_time:.2f}s") print(f" Accuracy: {sparse_metrics.get('accuracy', 'N/A')}") - print(f" Correct predictions: {sparse_metrics.get('correct_predictions', 'N/A')}/{sparse_metrics.get('total_samples', 'N/A')}") - + print( + f" Correct predictions: {sparse_metrics.get('correct_predictions', 'N/A')}/{sparse_metrics.get('total_samples', 'N/A')}" + ) + print("\n๐Ÿ“‹ Results Summary:") print(f" โ€ข Benchmark: {sparse_metrics['summary']['benchmark']}") print(f" โ€ข Task: {sparse_metrics['summary']['task']}") print(f" โ€ข Unique contexts: {sparse_metrics['summary']['unique_contexts']}") print(f" โ€ข Evaluation method: {sparse_metrics['summary']['evaluation_method']}") - + print(f"\n๐Ÿ’พ Results saved to: {sparse_dir}") print(" - raw_results.csv: Detailed predictions for each sample") print(" - metrics.json: Evaluation metrics and summary") if __name__ == "__main__": - main() + main() diff --git a/tutorials/py_examples/04_streaming_llm_benchmark_demo.py b/tutorials/py_examples/04_streaming_llm_benchmark_demo.py index e5dd22cb..ba249b1a 100644 --- a/tutorials/py_examples/04_streaming_llm_benchmark_demo.py +++ b/tutorials/py_examples/04_streaming_llm_benchmark_demo.py @@ -32,12 +32,16 @@ # Ensure we're in the correct directory and add to Python path import sys -os.chdir('/data/apdesai/code/sparse-attention-hub') -sys.path.insert(0, '/data/apdesai/code/sparse-attention-hub') -from sparse_attention_hub.sparse_attention.research_attention import ResearchAttentionConfig +os.chdir("/data/apdesai/code/sparse-attention-hub") +sys.path.insert(0, "/data/apdesai/code/sparse-attention-hub") + +from sparse_attention_hub.sparse_attention.research_attention import ( + ResearchAttentionConfig, +) from sparse_attention_hub.sparse_attention.research_attention.maskers.fixed.implementations import ( - LocalMaskerConfig, SinkMaskerConfig + LocalMaskerConfig, + SinkMaskerConfig, ) from sparse_attention_hub.adapters.huggingface import ModelAdapterHF from benchmark import Benchmark, LongBench, MockBenchmark @@ -45,18 +49,18 @@ class BenchmarkRunner: """Comprehensive benchmark runner for streaming attention evaluation.""" - + def __init__( - self, + self, model_name: str = "microsoft/Phi-4-mini-instruct", device: str = "cuda", sink_size: int = 4, local_window: int = 64, result_dir: str = "./benchmark_results", - benchmark_type: str = "mock" + benchmark_type: str = "mock", ): """Initialize the benchmark runner. - + Args: model_name: HuggingFace model identifier device: Device to run on ('cuda' or 'cpu') @@ -66,73 +70,73 @@ def __init__( benchmark_type: Type of benchmark to use ('mock' or 'longbench') """ self.model_name = model_name - self.device = torch.device(device if torch.cuda.is_available() else 'cpu') + self.device = torch.device(device if torch.cuda.is_available() else "cpu") self.sink_size = sink_size self.local_window = local_window self.result_dir = Path(result_dir) self.result_dir.mkdir(exist_ok=True) self.benchmark_type = benchmark_type - + print(f"๐Ÿš€ Initializing Benchmark Runner") print(f" Model: {model_name}") print(f" Device: {self.device}") print(f" Benchmark: {benchmark_type.upper()}") print(f" StreamingLLM Config: Sink({sink_size}) + Local({local_window})") print(f" Results will be saved to: {self.result_dir}") - + # Create StreamingLLM configuration self.streaming_config = self._create_streaming_config() - + # Initialize adapters self.dense_adapter = None self.sparse_adapter = None - + def _create_streaming_config(self) -> ResearchAttentionConfig: """Create StreamingLLM attention configuration.""" sink_config = SinkMaskerConfig(sink_size=self.sink_size) local_config = LocalMaskerConfig(window_size=self.local_window) return ResearchAttentionConfig(masker_configs=[sink_config, local_config]) - + def initialize_adapters(self) -> None: """Initialize both dense and sparse attention adapters.""" print("๐Ÿ”ง Initializing model adapters...") - + # Common model arguments common_kwargs = { "model_kwargs": {"torch_dtype": torch.bfloat16}, - "device": str(self.device) + "device": str(self.device), } - + # Dense adapter (no sparse attention) print(" โœ“ Loading dense attention adapter...") self.dense_adapter = ModelAdapterHF( model_name=self.model_name, sparse_attention_config=None, # No sparse attention = dense mode - **common_kwargs + **common_kwargs, ) - + # Sparse adapter (StreamingLLM) print(" โœ“ Loading sparse attention adapter...") self.sparse_adapter = ModelAdapterHF( model_name=self.model_name, sparse_attention_config=self.streaming_config, - **common_kwargs + **common_kwargs, ) - + print("โœ… Adapters initialized successfully!") - + def run_benchmark_comparison( - self, + self, benchmark_subsets: Optional[List[str]] = None, - max_samples: Optional[int] = 10 + max_samples: Optional[int] = 10, ) -> Dict[str, Dict]: """Run benchmark comparison between dense and sparse attention. - + Args: benchmark_subsets: List of benchmark subsets to run. For MockBenchmark, this parameter is ignored. For LongBench, if None, uses a small default set. max_samples: Maximum number of samples per subset for quick testing (ignored for MockBenchmark) - + Returns: Dictionary containing results for both dense and sparse runs """ @@ -147,103 +151,109 @@ def run_benchmark_comparison( if benchmark_subsets is None: # Use a small subset for demonstration benchmark_subsets = ["narrativeqa", "qasper", "samsum"] - + print(f"๐Ÿงช Running LongBench comparison on subsets: {benchmark_subsets}") benchmark = LongBench(subsets_to_run=benchmark_subsets) - + results = {} - + # Run dense attention benchmark print("\n๐Ÿ“Š Running Dense Attention Benchmark...") if self.dense_adapter is None: - raise RuntimeError("Dense adapter not initialized. Call initialize_adapters() first.") - results['dense'] = self._run_single_benchmark( + raise RuntimeError( + "Dense adapter not initialized. Call initialize_adapters() first." + ) + results["dense"] = self._run_single_benchmark( adapter=self.dense_adapter, benchmark=benchmark, mode_name="dense", - max_samples=max_samples + max_samples=max_samples, ) - + # Run sparse attention benchmark print("\nโšก Running Sparse Attention Benchmark...") if self.sparse_adapter is None: - raise RuntimeError("Sparse adapter not initialized. Call initialize_adapters() first.") - results['sparse'] = self._run_single_benchmark( + raise RuntimeError( + "Sparse adapter not initialized. Call initialize_adapters() first." + ) + results["sparse"] = self._run_single_benchmark( adapter=self.sparse_adapter, benchmark=benchmark, mode_name="sparse", - max_samples=max_samples + max_samples=max_samples, ) - + return results - + def _run_single_benchmark( - self, - adapter: ModelAdapterHF, - benchmark: Benchmark, + self, + adapter: ModelAdapterHF, + benchmark: Benchmark, mode_name: str, - max_samples: Optional[int] = None + max_samples: Optional[int] = None, ) -> Dict: """Run benchmark with a single adapter and track performance metrics. - + Args: adapter: The model adapter to use benchmark: The benchmark instance mode_name: Name for this benchmark run ('dense' or 'sparse') max_samples: Maximum samples to process (for quick testing) - + Returns: Dictionary containing benchmark results and performance metrics """ # Start memory tracking tracemalloc.start() start_time = time.time() - + # Create timestamped result directory timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") mode_result_dir = self.result_dir / f"{mode_name}_{timestamp}" mode_result_dir.mkdir(exist_ok=True) - + try: # Load and optionally limit dataset size print(f" ๐Ÿ“‹ Loading {mode_name} benchmark data...") dataset_df = benchmark._load_datasets() - + if max_samples: - print(f" โœ‚๏ธ Limiting to {max_samples} samples per task for quick testing") - dataset_df = dataset_df.groupby('task').head(max_samples).reset_index(drop=True) - + print( + f" โœ‚๏ธ Limiting to {max_samples} samples per task for quick testing" + ) + dataset_df = ( + dataset_df.groupby("task").head(max_samples).reset_index(drop=True) + ) + print(f" ๐Ÿ“ˆ Processing {len(dataset_df)} samples...") - + # Run the benchmark if mode_name == "sparse": # Use sparse attention mode with adapter.enable_sparse_mode(): metrics = benchmark.run_benchmark( - adapter=adapter, - result_dir=str(mode_result_dir) + adapter=adapter, result_dir=str(mode_result_dir) ) else: - # Use dense attention mode + # Use dense attention mode metrics = benchmark.run_benchmark( - adapter=adapter, - result_dir=str(mode_result_dir) + adapter=adapter, result_dir=str(mode_result_dir) ) - + # Track performance metrics end_time = time.time() current, peak = tracemalloc.get_traced_memory() tracemalloc.stop() - + # Compile results performance_metrics = { "execution_time_seconds": end_time - start_time, "peak_memory_mb": peak / 1024 / 1024, "current_memory_mb": current / 1024 / 1024, "samples_processed": len(dataset_df), - "avg_time_per_sample": (end_time - start_time) / len(dataset_df) + "avg_time_per_sample": (end_time - start_time) / len(dataset_df), } - + result = { "benchmark_metrics": metrics, "performance_metrics": performance_metrics, @@ -251,129 +261,157 @@ def _run_single_benchmark( "model_config": { "model_name": self.model_name, "mode": mode_name, - "streaming_config": { - "sink_size": self.sink_size, - "local_window": self.local_window - } if mode_name == "sparse" else None - } + "streaming_config": ( + {"sink_size": self.sink_size, "local_window": self.local_window} + if mode_name == "sparse" + else None + ), + }, } - + # Save detailed results with open(mode_result_dir / "detailed_results.json", "w") as f: json.dump(result, f, indent=2, default=str) - + print(f" โœ… {mode_name.title()} benchmark completed!") print(f" Time: {performance_metrics['execution_time_seconds']:.2f}s") print(f" Peak Memory: {performance_metrics['peak_memory_mb']:.1f}MB") print(f" Avg Score: {metrics.get('average_score', 'N/A')}") - + return result - + except Exception as e: print(f" โŒ Error in {mode_name} benchmark: {str(e)}") tracemalloc.stop() raise e - + def analyze_results(self, results: Dict[str, Dict]) -> None: """Analyze and visualize benchmark comparison results. - + Args: results: Results dictionary from run_benchmark_comparison """ print("\n๐Ÿ“Š Analyzing Results...") - + # Extract metrics for comparison - dense_metrics = results['dense']['performance_metrics'] - sparse_metrics = results['sparse']['performance_metrics'] - - dense_benchmark = results['dense']['benchmark_metrics'] - sparse_benchmark = results['sparse']['benchmark_metrics'] - + dense_metrics = results["dense"]["performance_metrics"] + sparse_metrics = results["sparse"]["performance_metrics"] + + dense_benchmark = results["dense"]["benchmark_metrics"] + sparse_benchmark = results["sparse"]["benchmark_metrics"] + # Performance comparison print("\n๐Ÿ“ˆ Performance Comparison:") print("โ”€" * 50) print(f"{'Metric':<25} {'Dense':<15} {'Sparse':<15} {'Speedup':<10}") print("โ”€" * 50) - - time_speedup = dense_metrics['execution_time_seconds'] / sparse_metrics['execution_time_seconds'] - memory_reduction = (dense_metrics['peak_memory_mb'] - sparse_metrics['peak_memory_mb']) / dense_metrics['peak_memory_mb'] * 100 - - print(f"{'Execution Time (s)':<25} {dense_metrics['execution_time_seconds']:<15.2f} {sparse_metrics['execution_time_seconds']:<15.2f} {time_speedup:<10.2f}x") - print(f"{'Peak Memory (MB)':<25} {dense_metrics['peak_memory_mb']:<15.1f} {sparse_metrics['peak_memory_mb']:<15.1f} {memory_reduction:<10.1f}%") - print(f"{'Avg Time/Sample (s)':<25} {dense_metrics['avg_time_per_sample']:<15.3f} {sparse_metrics['avg_time_per_sample']:<15.3f}") - + + time_speedup = ( + dense_metrics["execution_time_seconds"] + / sparse_metrics["execution_time_seconds"] + ) + memory_reduction = ( + (dense_metrics["peak_memory_mb"] - sparse_metrics["peak_memory_mb"]) + / dense_metrics["peak_memory_mb"] + * 100 + ) + + print( + f"{'Execution Time (s)':<25} {dense_metrics['execution_time_seconds']:<15.2f} {sparse_metrics['execution_time_seconds']:<15.2f} {time_speedup:<10.2f}x" + ) + print( + f"{'Peak Memory (MB)':<25} {dense_metrics['peak_memory_mb']:<15.1f} {sparse_metrics['peak_memory_mb']:<15.1f} {memory_reduction:<10.1f}%" + ) + print( + f"{'Avg Time/Sample (s)':<25} {dense_metrics['avg_time_per_sample']:<15.3f} {sparse_metrics['avg_time_per_sample']:<15.3f}" + ) + # Accuracy comparison print("\n๐ŸŽฏ Accuracy Comparison:") print("โ”€" * 40) - dense_score = dense_benchmark.get('average_score', 0) - sparse_score = sparse_benchmark.get('average_score', 0) - accuracy_retention = (sparse_score / dense_score * 100) if dense_score > 0 else 0 - + dense_score = dense_benchmark.get("average_score", 0) + sparse_score = sparse_benchmark.get("average_score", 0) + accuracy_retention = ( + (sparse_score / dense_score * 100) if dense_score > 0 else 0 + ) + print(f"Dense Attention Score: {dense_score:.3f}") print(f"Sparse Attention Score: {sparse_score:.3f}") print(f"Accuracy Retention: {accuracy_retention:.1f}%") - + # Create visualization self._create_visualization(results) - + # Summary print(f"\n๐Ÿ† Summary:") print(f" StreamingLLM achieves {time_speedup:.2f}x speedup") print(f" Reduces memory usage by {memory_reduction:.1f}%") print(f" Retains {accuracy_retention:.1f}% of original accuracy") - + def _create_visualization(self, results: Dict[str, Dict]) -> None: """Create visualization comparing dense vs sparse performance.""" try: import matplotlib.pyplot as plt - + fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(12, 10)) - fig.suptitle('Dense vs Sparse Attention Benchmark Comparison', fontsize=16) - + fig.suptitle("Dense vs Sparse Attention Benchmark Comparison", fontsize=16) + # Extract data - dense_perf = results['dense']['performance_metrics'] - sparse_perf = results['sparse']['performance_metrics'] - dense_bench = results['dense']['benchmark_metrics'] - sparse_bench = results['sparse']['benchmark_metrics'] - + dense_perf = results["dense"]["performance_metrics"] + sparse_perf = results["sparse"]["performance_metrics"] + dense_bench = results["dense"]["benchmark_metrics"] + sparse_bench = results["sparse"]["benchmark_metrics"] + # Execution time comparison - times = [dense_perf['execution_time_seconds'], sparse_perf['execution_time_seconds']] - ax1.bar(['Dense', 'Sparse'], times, color=['#ff7f0e', '#2ca02c']) - ax1.set_ylabel('Execution Time (seconds)') - ax1.set_title('Execution Time Comparison') - + times = [ + dense_perf["execution_time_seconds"], + sparse_perf["execution_time_seconds"], + ] + ax1.bar(["Dense", "Sparse"], times, color=["#ff7f0e", "#2ca02c"]) + ax1.set_ylabel("Execution Time (seconds)") + ax1.set_title("Execution Time Comparison") + # Memory usage comparison - memories = [dense_perf['peak_memory_mb'], sparse_perf['peak_memory_mb']] - ax2.bar(['Dense', 'Sparse'], memories, color=['#ff7f0e', '#2ca02c']) - ax2.set_ylabel('Peak Memory (MB)') - ax2.set_title('Memory Usage Comparison') - + memories = [dense_perf["peak_memory_mb"], sparse_perf["peak_memory_mb"]] + ax2.bar(["Dense", "Sparse"], memories, color=["#ff7f0e", "#2ca02c"]) + ax2.set_ylabel("Peak Memory (MB)") + ax2.set_title("Memory Usage Comparison") + # Accuracy comparison - scores = [dense_bench.get('average_score', 0), sparse_bench.get('average_score', 0)] - ax3.bar(['Dense', 'Sparse'], scores, color=['#ff7f0e', '#2ca02c']) - ax3.set_ylabel('Average Score') - ax3.set_title('Accuracy Comparison') + scores = [ + dense_bench.get("average_score", 0), + sparse_bench.get("average_score", 0), + ] + ax3.bar(["Dense", "Sparse"], scores, color=["#ff7f0e", "#2ca02c"]) + ax3.set_ylabel("Average Score") + ax3.set_title("Accuracy Comparison") ax3.set_ylim(0, 1) - + # Per-sample time comparison - per_sample_times = [dense_perf['avg_time_per_sample'], sparse_perf['avg_time_per_sample']] - ax4.bar(['Dense', 'Sparse'], per_sample_times, color=['#ff7f0e', '#2ca02c']) - ax4.set_ylabel('Time per Sample (seconds)') - ax4.set_title('Per-Sample Processing Time') - + per_sample_times = [ + dense_perf["avg_time_per_sample"], + sparse_perf["avg_time_per_sample"], + ] + ax4.bar(["Dense", "Sparse"], per_sample_times, color=["#ff7f0e", "#2ca02c"]) + ax4.set_ylabel("Time per Sample (seconds)") + ax4.set_title("Per-Sample Processing Time") + plt.tight_layout() - + # Save plot - plot_path = self.result_dir / f"benchmark_comparison_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png" - plt.savefig(plot_path, dpi=300, bbox_inches='tight') + plot_path = ( + self.result_dir + / f"benchmark_comparison_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png" + ) + plt.savefig(plot_path, dpi=300, bbox_inches="tight") print(f"๐Ÿ“Š Visualization saved to: {plot_path}") - + # Also try to show if in interactive environment try: plt.show() except: pass - + except ImportError: print("๐Ÿ“Š Matplotlib not available for visualization") except Exception as e: @@ -383,31 +421,47 @@ def _create_visualization(self, results: Dict[str, Dict]) -> None: def main(): """Main function to run the streaming LLM benchmark demo.""" parser = argparse.ArgumentParser(description="Streaming LLM Benchmark Demo") - parser.add_argument("--model", default="microsoft/Phi-4-mini-instruct", - help="HuggingFace model name") - parser.add_argument("--benchmark", default="mock", choices=["mock", "longbench"], - help="Benchmark type: 'mock' for quick testing (5 samples) or 'longbench' for comprehensive evaluation") - parser.add_argument("--subsets", default="narrativeqa,qasper,samsum", - help="Comma-separated list of LongBench subsets (ignored for MockBenchmark)") - parser.add_argument("--max-samples", type=int, default=5, - help="Maximum samples per subset for quick testing (ignored for MockBenchmark)") - parser.add_argument("--sink-size", type=int, default=4, - help="Number of sink tokens") - parser.add_argument("--local-window", type=int, default=64, - help="Local attention window size") - parser.add_argument("--device", default="cuda", - help="Device to use (cuda/cpu)") - parser.add_argument("--result-dir", default="./benchmark_results", - help="Directory to save results") - + parser.add_argument( + "--model", + default="microsoft/Phi-4-mini-instruct", + help="HuggingFace model name", + ) + parser.add_argument( + "--benchmark", + default="mock", + choices=["mock", "longbench"], + help="Benchmark type: 'mock' for quick testing (5 samples) or 'longbench' for comprehensive evaluation", + ) + parser.add_argument( + "--subsets", + default="narrativeqa,qasper,samsum", + help="Comma-separated list of LongBench subsets (ignored for MockBenchmark)", + ) + parser.add_argument( + "--max-samples", + type=int, + default=5, + help="Maximum samples per subset for quick testing (ignored for MockBenchmark)", + ) + parser.add_argument( + "--sink-size", type=int, default=4, help="Number of sink tokens" + ) + parser.add_argument( + "--local-window", type=int, default=64, help="Local attention window size" + ) + parser.add_argument("--device", default="cuda", help="Device to use (cuda/cpu)") + parser.add_argument( + "--result-dir", default="./benchmark_results", help="Directory to save results" + ) + args = parser.parse_args() - + print("๐ŸŽฏ Streaming LLM Benchmark Demo") print("=" * 50) - + # Parse subsets subsets = [s.strip() for s in args.subsets.split(",")] - + # Initialize benchmark runner runner = BenchmarkRunner( model_name=args.model, @@ -415,24 +469,23 @@ def main(): sink_size=args.sink_size, local_window=args.local_window, result_dir=args.result_dir, - benchmark_type=args.benchmark + benchmark_type=args.benchmark, ) - + # Initialize adapters runner.initialize_adapters() - + # Run benchmark comparison results = runner.run_benchmark_comparison( - benchmark_subsets=subsets, - max_samples=args.max_samples + benchmark_subsets=subsets, max_samples=args.max_samples ) - + # Analyze results runner.analyze_results(results) - + print("\nโœ… Benchmark demo completed successfully!") print(f"๐Ÿ“ Results saved to: {runner.result_dir}") if __name__ == "__main__": - main() + main() diff --git a/tutorials/py_examples/05_local_sink_oracle_adaptive_demo.py b/tutorials/py_examples/05_local_sink_oracle_adaptive_demo.py index ba2954ee..f666e62a 100644 --- a/tutorials/py_examples/05_local_sink_oracle_adaptive_demo.py +++ b/tutorials/py_examples/05_local_sink_oracle_adaptive_demo.py @@ -23,15 +23,20 @@ # Ensure we're in the correct directory and add to Python path import sys -os.chdir('/data/apdesai/code/sparse-attention-hub') -sys.path.insert(0, '/data/apdesai/code/sparse-attention-hub') -from sparse_attention_hub.sparse_attention.research_attention import ResearchAttentionConfig +os.chdir("/data/apdesai/code/sparse-attention-hub") +sys.path.insert(0, "/data/apdesai/code/sparse-attention-hub") + +from sparse_attention_hub.sparse_attention.research_attention import ( + ResearchAttentionConfig, +) from sparse_attention_hub.sparse_attention.research_attention.maskers.fixed.implementations import ( - LocalMaskerConfig, SinkMaskerConfig, OracleTopKConfig + LocalMaskerConfig, + SinkMaskerConfig, + OracleTopKConfig, ) from sparse_attention_hub.sparse_attention.research_attention.maskers.sampling.implementations import ( - AdaptiveSamplingMaskerConfig + AdaptiveSamplingMaskerConfig, ) from sparse_attention_hub.adapters.huggingface import ModelAdapterHF from sparse_attention_hub.adapters import Request @@ -39,79 +44,80 @@ def main(): """Run a demo with combined maskers: Local + Sink + Oracle-TopK + Adaptive Sampling.""" - + print("๐ŸŽฏ Local + Sink + Oracle-TopK + Adaptive Sampling Demo") print("=" * 60) - + # Configuration model_name = "microsoft/Phi-4-mini-instruct" # Small model for quick testing - device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') - + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + print(f"Model: {model_name}") print(f"Device: {device}") - + # Create combined masker configuration print("\n๐Ÿ”ง Creating combined masker configuration...") - + # 1. Local masker: 4-token window for local attention local_config = LocalMaskerConfig(window_size=4) print(" โœ“ LocalMasker: window_size=4") - + # 2. Sink masker: 4 sink tokens for global information sink_config = SinkMaskerConfig(sink_size=4) print(" โœ“ SinkMasker: sink_size=4") - + # 3. Oracle-TopK masker: 4 tokens based on oracle attention scores oracle_config = OracleTopKConfig(heavy_size=4) print(" โœ“ OracleTopKMasker: heavy_size=4") - + # 4. Adaptive sampling masker: 10% base rate with statistical guarantees adaptive_config = AdaptiveSamplingMaskerConfig( base_rate_sampling=0.1, # 10% base sampling rate - epsilon=0.1, # Error bound - delta=0.05, # Confidence bound - init_offset=4, # Start from beginning - local_offset=4 # End at sequence end + epsilon=0.1, # Error bound + delta=0.05, # Confidence bound + init_offset=4, # Start from beginning + local_offset=4, # End at sequence end ) print(" โœ“ AdaptiveSamplingMasker: base_rate=0.1, epsilon=0.1, delta=0.05") - + # Combine all maskers in order of application combined_config = ResearchAttentionConfig( - masker_configs=[local_config, - sink_config, - oracle_config, - adaptive_config, + masker_configs=[ + local_config, + sink_config, + oracle_config, + adaptive_config, ] ) - + print("\n๐Ÿ“‹ Combined Configuration:") print(" โ€ข Local(4) + Sink(4) + Oracle-TopK(4) + Adaptive(0.1)") print(" โ€ข Total maskers: 4") print(" โ€ข Expected sparsity: High (multiple sparse patterns combined)") - + # Common model arguments model_kwargs = { "model_kwargs": {"torch_dtype": torch.bfloat16}, - "device": str(device) + "device": str(device), } - + # Initialize adapter print("\n๐Ÿ”ง Loading model with combined maskers...") - + try: adapter = ModelAdapterHF( model_name=model_name, sparse_attention_config=combined_config, - **model_kwargs + **model_kwargs, ) print(" โœ… Successfully loaded model with combined maskers") except Exception as e: print(f" โŒ Error loading model: {e}") return - + # Prepare test input print("\n๐Ÿ“ Preparing test input...") - + test_context = """ The sparse attention mechanism combines multiple attention patterns to achieve both computational efficiency and performance. This approach uses: @@ -124,50 +130,55 @@ def main(): This combination allows the model to maintain high performance while significantly reducing computational complexity for long sequences. """ - + test_questions = [ "What are the four attention patterns used in this sparse attention mechanism?", "How does adaptive sampling contribute to the overall efficiency?", - "Explain the difference between local and sink attention patterns." + "Explain the difference between local and sink attention patterns.", ] - + request = Request( context=test_context, questions=test_questions, ) - + print(f" โœ“ Context length: {len(test_context.split())} words") print(f" โœ“ Number of questions: {len(test_questions)}") - + # Run inference print("\n๐Ÿงช Running inference with combined maskers...") start_time = time.time() - + try: - response = adapter.process_request(request, generation_kwargs={"max_new_tokens": 100}, request_kwargs={"max_context": 1024}) + response = adapter.process_request( + request, + generation_kwargs={"max_new_tokens": 100}, + request_kwargs={"max_context": 1024}, + ) response_text = response.responses - + inference_time = time.time() - start_time print(f" โœ… Inference completed in {inference_time:.2f}s") - + # Display results print("\n๐Ÿ“Š Results:") print("-" * 40) - + for i, (question, answer) in enumerate(zip(test_questions, response_text), 1): print(f"\nQ{i}: {question}") print(f"A{i}: {answer}") - + except Exception as e: print(f" โŒ Error during inference: {e}") import traceback + traceback.print_exc() return - + # Performance analysis print("\n๐Ÿ“ˆ Performance Analysis:") print("-" * 40) - + # Calculate expected sparsity # This is a rough estimate based on the masker configurations print(" โ€ข Local attention: ~25% sparsity (4-token window)") @@ -175,18 +186,20 @@ def main(): print(" โ€ข Oracle-TopK: ~25% sparsity (4 top tokens)") print(" โ€ข Adaptive sampling: ~10% base rate + adaptive budget") print(" โ€ข Combined effect: High sparsity with maintained performance") - + print("\n๐Ÿ’ก Key Benefits:") print(" โ€ข Local attention captures immediate context") print(" โ€ข Sink attention preserves global information") print(" โ€ข Oracle attention selects most relevant tokens") print(" โ€ข Adaptive sampling provides statistical guarantees") print(" โ€ข Combined approach balances efficiency and performance") - + print(f"\nโœ… Demo completed successfully!") print(" The combined masker approach demonstrates how different attention") - print(" patterns can be layered to create sophisticated sparse attention mechanisms.") + print( + " patterns can be layered to create sophisticated sparse attention mechanisms." + ) if __name__ == "__main__": - main() + main()