├── test ├── __init__.py ├── config │ ├── __init__.py │ └── test_client.py └── test_synthetic.py ├── syncora_sdk ├── exceptions.py ├── models │ ├── __init__.py │ └── synthetic.py ├── schemas │ ├── __init__.py │ ├── dto │ │ ├── __init__.py │ │ ├── Base.py │ │ ├── SyntheticDataDto.py │ │ └── EncryptedApiKeyDto.py │ ├── constants │ │ ├── __init__.py │ │ └── literal.py │ └── synthetic.py ├── storage │ ├── __init__.py │ └── s3.py ├── utils │ ├── __init__.py │ └── http │ │ ├── __init.py │ │ └── raise_for_status_with_details.py ├── __init__.py ├── test_request.py └── client.py ├── pyproject.toml ├── LICENSE ├── .gitignore ├── README.md └── poetry.lock /test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/config/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/test_synthetic.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncora_sdk/exceptions.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncora_sdk/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncora_sdk/schemas/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncora_sdk/storage/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncora_sdk/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncora_sdk/utils/http/__init.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncora_sdk/schemas/dto/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncora_sdk/schemas/constants/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /syncora_sdk/schemas/constants/literal.py: -------------------------------------------------------------------------------- 1 | from typing import Literal 2 | 3 | FileType = Literal["Tabular", "JSONL", "Images", "Text", "Timeseries"] 4 | -------------------------------------------------------------------------------- /syncora_sdk/__init__.py: -------------------------------------------------------------------------------- 1 | from syncora_sdk.client import SyncoraClient 2 | from syncora_sdk.models.synthetic import SyntheticDataGenerator 3 | 4 | __all__ = ["SyncoraClient", "SyntheticDataGenerator"] -------------------------------------------------------------------------------- /syncora_sdk/schemas/dto/Base.py: -------------------------------------------------------------------------------- 1 | class BaseDto: 2 | def __init__(self, data: dict | None): 3 | self._raw = data 4 | self.data = data.get("data") if data is not None else None 5 | -------------------------------------------------------------------------------- /syncora_sdk/schemas/dto/SyntheticDataDto.py: -------------------------------------------------------------------------------- 1 | from syncora_sdk.schemas.dto.Base import BaseDto 2 | 3 | 4 | class SyntheticDataDto(BaseDto): 5 | def __init__(self, data: dict): 6 | super().__init__(data) 7 | self.data = self.data.get("fileUrl") 8 | -------------------------------------------------------------------------------- /syncora_sdk/schemas/synthetic.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, HttpUrl 2 | 3 | class SyntheticDataRequest(BaseModel): 4 | fileUrl: HttpUrl 5 | type: str 6 | numberOfRows: int 7 | fileSizeBytes: int 8 | sourceFileRows: int 9 | targetColumn: str -------------------------------------------------------------------------------- /syncora_sdk/schemas/dto/EncryptedApiKeyDto.py: -------------------------------------------------------------------------------- 1 | from syncora_sdk.schemas.dto.Base import BaseDto 2 | 3 | 4 | class EncryptedApiKeyDto(BaseDto): 5 | def __init__(self, data: dict): 6 | super().__init__(data) 7 | self.data = self.data.get("encryptedApiKey") 8 | -------------------------------------------------------------------------------- /syncora_sdk/test_request.py: -------------------------------------------------------------------------------- 1 | import httpx 2 | from typing import TypedDict 3 | from datetime import date 4 | 5 | 6 | class Data(TypedDict): 7 | id: int 8 | name: str 9 | email: str 10 | date: date 11 | 12 | 13 | def main(data: Data) -> None: 14 | data["id"] 15 | # make the request 16 | url = "https://httpbin.org/get" 17 | response = httpx.get(url) 18 | print(response.headers) 19 | print("response json", response.json()) 20 | 21 | 22 | # main() 23 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "syncora-sdk" 3 | version = "0.1.3" 4 | description = "Python SDK for Syncora.ai AI models" 5 | authors = [ 6 | {name = "ashish@kreedalabs"} 7 | ] 8 | license = "MIT" 9 | readme = "README.md" 10 | packages = [{ include = "syncora_sdk" }] 11 | requires-python = ">=3.13" 12 | dependencies = [ 13 | "httpx (>=0.28.1,<0.29.0)", 14 | "pydantic (>=2.11.7,<3.0.0)", 15 | "pytest (>=8.4.1,<9.0.0)" 16 | ] 17 | 18 | 19 | [build-system] 20 | requires = ["poetry-core>=2.0.0,<3.0.0"] 21 | build-backend = "poetry.core.masonry.api" 22 | -------------------------------------------------------------------------------- /syncora_sdk/utils/http/raise_for_status_with_details.py: -------------------------------------------------------------------------------- 1 | import httpx 2 | 3 | 4 | def raise_for_status_with_details(response: httpx.Response): 5 | """ 6 | Raises an HTTPStatusError with additional response body info 7 | if the response status is not 2xx. 8 | """ 9 | try: 10 | response.raise_for_status() 11 | except httpx.HTTPStatusError as e: 12 | try: 13 | error_detail = response.json() 14 | except Exception: 15 | error_detail = response.text or str(e) 16 | 17 | raise RuntimeError(error_detail) from e 18 | -------------------------------------------------------------------------------- /syncora_sdk/storage/s3.py: -------------------------------------------------------------------------------- 1 | import httpx 2 | from syncora_sdk.client import SyncoraClient 3 | from pydantic import HttpUrl 4 | from pathlib import Path 5 | from syncora_sdk.schemas.dto.Base import BaseDto 6 | 7 | 8 | class S3Uploder: 9 | def __init__(self, client: SyncoraClient): 10 | self.client = client 11 | 12 | def get_presigned_url(self, fileName: str) -> dict | None: 13 | response = self.client.post( 14 | "/ai/get-presigned-url", 15 | json={"filename": fileName, "contentType": "text/csv"}, 16 | ) 17 | data = BaseDto(response).data 18 | return data 19 | 20 | def upload_file(self, upload_url: HttpUrl, file_path: Path): 21 | file = Path(file_path) 22 | if not file.exists(): 23 | raise FileNotFoundError(f"File not found : {file_path}") 24 | with open(file, "rb") as f: 25 | response = httpx.put(str(upload_url), content=f.read()) 26 | response.raise_for_status() 27 | return True 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 keedaAsh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /syncora_sdk/client.py: -------------------------------------------------------------------------------- 1 | import httpx 2 | from syncora_sdk.schemas.synthetic import SyntheticDataRequest 3 | from syncora_sdk.schemas.dto.EncryptedApiKeyDto import EncryptedApiKeyDto 4 | from syncora_sdk.utils.http.raise_for_status_with_details import ( 5 | raise_for_status_with_details, 6 | ) 7 | 8 | 9 | class SyncoraClient: 10 | def __init__(self, api_key: str) -> None: 11 | 12 | self.api_key = self.generateTheHash(api_key) 13 | self.client = httpx.Client( 14 | base_url="https://api.syncora.ai/api/v1", 15 | headers={"x-api-key": self.api_key}, 16 | timeout=None, 17 | ) 18 | 19 | def generateTheHash(self, x_api_key: str) -> str: 20 | response = httpx.post( 21 | "https://api.syncora.ai/api/v1/credentials/api/encrypt", 22 | json={"apiKey": x_api_key}, 23 | ) 24 | 25 | raise_for_status_with_details(response) 26 | 27 | data = response.json() 28 | 29 | enc_key = EncryptedApiKeyDto(data).data 30 | if not enc_key: 31 | raise ValueError( 32 | "Encryption failed: 'encryptedApiKey' missing in response." 33 | ) 34 | 35 | return enc_key 36 | 37 | def post(self, path: str, json): 38 | response = self.client.post(path, json=json) 39 | raise_for_status_with_details(response) 40 | return response.json() 41 | 42 | def close(self): 43 | self.client.close() 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # Virtual environment 27 | venv/ 28 | ENV/ 29 | env/ 30 | .venv/ 31 | env.bak/ 32 | venv.bak/ 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .nox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | *.py,cover 49 | 50 | # Pytest 51 | .pytest_cache/ 52 | pytestdebug.log 53 | 54 | # Cython debug symbols 55 | cython_debug/ 56 | 57 | # MyPy & type checking 58 | .mypy_cache/ 59 | .dmypy.json 60 | dmypy.json 61 | 62 | # Pyre type checker 63 | .pyre/ 64 | 65 | # PyCharm 66 | .idea/ 67 | 68 | # VSCode 69 | .vscode/ 70 | *.code-workspace 71 | 72 | # MacOS 73 | .DS_Store 74 | 75 | # Linux 76 | *~ 77 | 78 | # Windows 79 | Thumbs.db 80 | ehthumbs.db 81 | Desktop.ini 82 | 83 | # Editor backups 84 | *.swp 85 | *.swo 86 | 87 | # SDK specific 88 | docs/_build/ 89 | docs/api/ 90 | *.spec 91 | *.pyd 92 | 93 | # Jupyter 94 | .ipynb_checkpoints 95 | 96 | # Wheel files 97 | *.whl 98 | 99 | # Log files 100 | *.log 101 | 102 | # Build tools 103 | .mr.developer.cfg 104 | .pyre/ 105 | 106 | # Poetry 107 | # DON'T ignore poetry.lock 108 | # Ignore Poetry's virtualenv if it's inside project dir 109 | .venv/ 110 | .env 111 | 112 | 113 | #other local testing files 114 | Sonar.csv 115 | syntheticDataGenerator.py 116 | 117 | #other files 118 | FutureReadme.md -------------------------------------------------------------------------------- /test/config/test_client.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from unittest.mock import patch, MagicMock 3 | from syncora_sdk.client import SyncoraClient 4 | 5 | 6 | @pytest.fixture 7 | def client(): 8 | return SyncoraClient(api_key="test-api-key") 9 | 10 | 11 | dummy_api_key = "12345678910" 12 | 13 | 14 | @patch("syncora_sdk.client.httpx.Client.post") 15 | def test_generate_the_hash_success(mock_post, client): 16 | mock_response = MagicMock() 17 | mock_response.json.return_value = {"encryptedApiKey": "hashed-key-123"} 18 | mock_response.raise_for_status.return_value = None 19 | mock_post.return_value = mock_response 20 | 21 | result = client.generateTheHash(dummy_api_key) 22 | 23 | assert result == "hashed-key-123" 24 | mock_post.assert_called_once_with( 25 | "/credentials/api/encrypt", json={"apiKey": dummy_api_key} 26 | ) 27 | 28 | 29 | @patch("syncora_sdk.client.httpx.Client.post") 30 | def test_generate_the_hash_missing_key(mock_post, client): 31 | mock_response = MagicMock() 32 | mock_response.json.return_value = {} # No 'encryptedApiKey' 33 | mock_response.raise_for_status.return_value = None 34 | mock_post.return_value = mock_response 35 | 36 | with pytest.raises( 37 | ValueError, match="Encryption failed: 'encryptedApiKey' missing in response." 38 | ): 39 | client.generateTheHash(dummy_api_key) 40 | 41 | 42 | @patch("syncora_sdk.client.httpx.Client.post") 43 | def test_generate_the_hash_http_error(mock_post, client): 44 | mock_response = MagicMock() 45 | mock_response.raise_for_status.side_effect = Exception("HTTP error") 46 | mock_post.return_value = mock_response 47 | 48 | with pytest.raises(Exception, match="HTTP error"): 49 | client.generateTheHash(dummy_api_key) 50 | 51 | 52 | @patch("syncora_sdk.client.httpx.Client.post") 53 | def test_post_success(mock_post, client): 54 | mock_response = MagicMock() 55 | mock_response.json.return_value = {"result": "ok"} 56 | mock_response.raise_for_status.return_value = None 57 | mock_post.return_value = mock_response 58 | 59 | result = client.post("/some/path", json={"foo": "bar"}) 60 | 61 | assert result == {"result": "ok"} 62 | mock_post.assert_called_once_with("test-api-key", json={"foo": "bar"}) 63 | 64 | 65 | @patch("syncora_sdk.client.httpx.Client.post") 66 | def test_post_http_error(mock_post, client): 67 | mock_response = MagicMock() 68 | mock_response.raise_for_status.side_effect = Exception("Post failed") 69 | mock_post.return_value = mock_response 70 | 71 | with pytest.raises(Exception, match="Post failed"): 72 | client.post("/some/path", json={"foo": "bar"}) 73 | -------------------------------------------------------------------------------- /syncora_sdk/models/synthetic.py: -------------------------------------------------------------------------------- 1 | from syncora_sdk.client import SyncoraClient 2 | from syncora_sdk.schemas.constants.literal import FileType 3 | from syncora_sdk.storage.s3 import S3Uploder 4 | from syncora_sdk.schemas.synthetic import SyntheticDataRequest 5 | from pydantic import ValidationError, HttpUrl 6 | from pathlib import Path 7 | import csv 8 | from syncora_sdk.schemas.dto.SyntheticDataDto import SyntheticDataDto 9 | 10 | 11 | class SyntheticDataGenerator: 12 | def __init__(self, client: SyncoraClient): 13 | self.client = client 14 | self.s3 = S3Uploder(client) 15 | 16 | def generate( 17 | self, 18 | fileUrl: HttpUrl, 19 | type: FileType, 20 | numberOfRows: int, 21 | fileSizeBytes: int, 22 | sourceFileRows: int, 23 | targetColumn: str, 24 | ): 25 | try: 26 | paylaod = SyntheticDataRequest( 27 | fileUrl=fileUrl, 28 | type=type, 29 | numberOfRows=numberOfRows, 30 | fileSizeBytes=fileSizeBytes, 31 | sourceFileRows=sourceFileRows, 32 | targetColumn=targetColumn, 33 | ) 34 | except ValidationError as e: 35 | raise ValueError( 36 | f"Invalid parameters for synthetic data generation:\n{e}" 37 | ) from e 38 | print(f'generating data...') 39 | response = self.client.post("/ai/execute", json=paylaod.model_dump(mode="json")) 40 | return SyntheticDataDto(response).data 41 | 42 | def generate_from_file( 43 | self, file_path: Path, type: FileType, numberOfRows: int, targetColumn: str 44 | ): 45 | file = Path(file_path) 46 | file_size = file.stat().st_size 47 | 48 | with open(str(file_path), newline="") as csvfile: 49 | reader = csv.reader(csvfile) 50 | row_count = sum(1 for _ in reader) - 1 51 | 52 | filename = file.name 53 | 54 | # print(row_count) 55 | # print(file_size) 56 | # print(filename) 57 | 58 | urls = self.s3.get_presigned_url(fileName=filename) 59 | # print("signed url response", urls) 60 | if urls: 61 | # print(urls["uploadUrl"]) 62 | # print(urls["publicUrl"]) 63 | self.s3.upload_file(urls["uploadUrl"], file_path=file_path) 64 | return self.generate( 65 | fileUrl=urls["publicUrl"], 66 | type=type, 67 | numberOfRows=numberOfRows, 68 | fileSizeBytes=file_size, 69 | sourceFileRows=row_count, 70 | targetColumn=targetColumn, 71 | ) 72 | else: 73 | raise Exception("Failed to upload file") 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Syncora SDK 2 | 3 | Syncora SDK is a Python client library for interacting with the Syncora synthetic data platform. It allows you to generate high-quality synthetic datasets from a variety of sources including CSV, dataframes, and raw text. With just a few lines of code, you can bootstrap synthetic data pipelines in your analytics, testing, and machine learning workflows. 4 | 5 | --- 6 | 7 | ## Features 8 | 9 | * **Easy initialization** with API key or environment variable 10 | * **Multiple data sources**: CSV, Pandas DataFrame, JSON text 11 | * **Data types**: Tabular, Time-series, JSONL 12 | * **Flexible configuration**: Control number of rows, target columns, constraints 13 | * **Asynchronous support** for large datasets 14 | * **Built‑in error handling** and logging 15 | 16 | --- 17 | 18 | ## Installation 19 | 20 | Install the SDK via pip: 21 | 22 | ```bash 23 | pip install syncora-sdk 24 | ``` 25 | 26 | > Requires Python 3.7 or higher. 27 | 28 | --- 29 | 30 | ## Quick Start 31 | 32 | ### 1. Set your API key 33 | 34 | Head over to https://syncora.ai, register for an account, and generate your API key from the dashboard. 35 | 36 | ### 2. Initialize the client and generator 37 | 38 | ```python 39 | from syncora_sdk import SyncoraClient, SyntheticDataGenerator 40 | from pathlib import Path 41 | 42 | 43 | # Client with API key 44 | client = SyncoraClient(api_key="your-syncora-api-key") 45 | 46 | # Instantiate the synthetic data generator 47 | syntheticDataGenerator = SyntheticDataGenerator(client) 48 | ``` 49 | 50 | ### 3. Generate synthetic tabular data from a CSV file 51 | 52 | ```python 53 | file_path = Path("Sonar.csv") 54 | 55 | response = syntheticDataGenerator.generate_from_file( 56 | file_path=file_path, 57 | type="Tabular", 58 | numberOfRows=100, 59 | targetColumn="Freq_1" 60 | ) 61 | 62 | print(response) 63 | ``` 64 | 65 | This will return a JSON response with a link to download the generated synthetic dataset. 66 | 67 | --- 68 | 69 | ## API Reference 70 | 71 | ### `SyncoraClient` 72 | 73 | | Method | Description | 74 | | ------------------- | --------------------------------------------------------------- | 75 | | `__init__(api_key)` | Initialize client with your api key. | 76 | 77 | ### `SyntheticDataGenerator` 78 | 79 | | Method | Description | 80 | | ----------------------------------------------- | ------------------------------------------------------ | 81 | | `generate_from_file(file_path, type, ...)` | Generate synthetic data from a file (CSV, JSONL, etc.) | 82 | 83 | **Common Parameters**: 84 | 85 | * `type` (str): Type of data to generate. One of \[`"Tabular"`, `"TimeSeries"`, `"JSONL"`] 86 | * `numberOfRows` (int): Number of rows or records to generate. 87 | * `targetColumn` (str, optional): Column on which to focus generation for tabular data. 88 | --- 89 | 90 | ## Error Handling 91 | 92 | All SDK methods raise `SyncoraError` on failure. You can catch and inspect: 93 | 94 | ```python 95 | from syncora_sdk import SyncoraError 96 | 97 | try: 98 | syntheticDataGenerator.generate_from_file(...) 99 | except SyncoraError as e: 100 | print(f"Error: {e.code} – {e.message}") 101 | ``` 102 | 103 | --- 104 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "annotated-types" 5 | version = "0.7.0" 6 | description = "Reusable constraint types to use with typing.Annotated" 7 | optional = false 8 | python-versions = ">=3.8" 9 | groups = ["main"] 10 | files = [ 11 | {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, 12 | {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, 13 | ] 14 | 15 | [[package]] 16 | name = "anyio" 17 | version = "4.9.0" 18 | description = "High level compatibility layer for multiple asynchronous event loop implementations" 19 | optional = false 20 | python-versions = ">=3.9" 21 | groups = ["main"] 22 | files = [ 23 | {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"}, 24 | {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"}, 25 | ] 26 | 27 | [package.dependencies] 28 | idna = ">=2.8" 29 | sniffio = ">=1.1" 30 | 31 | [package.extras] 32 | doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] 33 | test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] 34 | trio = ["trio (>=0.26.1)"] 35 | 36 | [[package]] 37 | name = "certifi" 38 | version = "2025.7.14" 39 | description = "Python package for providing Mozilla's CA Bundle." 40 | optional = false 41 | python-versions = ">=3.7" 42 | groups = ["main"] 43 | files = [ 44 | {file = "certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2"}, 45 | {file = "certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995"}, 46 | ] 47 | 48 | [[package]] 49 | name = "colorama" 50 | version = "0.4.6" 51 | description = "Cross-platform colored terminal text." 52 | optional = false 53 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 54 | groups = ["main"] 55 | markers = "sys_platform == \"win32\"" 56 | files = [ 57 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 58 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 59 | ] 60 | 61 | [[package]] 62 | name = "h11" 63 | version = "0.16.0" 64 | description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" 65 | optional = false 66 | python-versions = ">=3.8" 67 | groups = ["main"] 68 | files = [ 69 | {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, 70 | {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, 71 | ] 72 | 73 | [[package]] 74 | name = "httpcore" 75 | version = "1.0.9" 76 | description = "A minimal low-level HTTP client." 77 | optional = false 78 | python-versions = ">=3.8" 79 | groups = ["main"] 80 | files = [ 81 | {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, 82 | {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, 83 | ] 84 | 85 | [package.dependencies] 86 | certifi = "*" 87 | h11 = ">=0.16" 88 | 89 | [package.extras] 90 | asyncio = ["anyio (>=4.0,<5.0)"] 91 | http2 = ["h2 (>=3,<5)"] 92 | socks = ["socksio (==1.*)"] 93 | trio = ["trio (>=0.22.0,<1.0)"] 94 | 95 | [[package]] 96 | name = "httpx" 97 | version = "0.28.1" 98 | description = "The next generation HTTP client." 99 | optional = false 100 | python-versions = ">=3.8" 101 | groups = ["main"] 102 | files = [ 103 | {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, 104 | {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, 105 | ] 106 | 107 | [package.dependencies] 108 | anyio = "*" 109 | certifi = "*" 110 | httpcore = "==1.*" 111 | idna = "*" 112 | 113 | [package.extras] 114 | brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] 115 | cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] 116 | http2 = ["h2 (>=3,<5)"] 117 | socks = ["socksio (==1.*)"] 118 | zstd = ["zstandard (>=0.18.0)"] 119 | 120 | [[package]] 121 | name = "idna" 122 | version = "3.10" 123 | description = "Internationalized Domain Names in Applications (IDNA)" 124 | optional = false 125 | python-versions = ">=3.6" 126 | groups = ["main"] 127 | files = [ 128 | {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, 129 | {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, 130 | ] 131 | 132 | [package.extras] 133 | all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] 134 | 135 | [[package]] 136 | name = "iniconfig" 137 | version = "2.1.0" 138 | description = "brain-dead simple config-ini parsing" 139 | optional = false 140 | python-versions = ">=3.8" 141 | groups = ["main"] 142 | files = [ 143 | {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, 144 | {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, 145 | ] 146 | 147 | [[package]] 148 | name = "packaging" 149 | version = "25.0" 150 | description = "Core utilities for Python packages" 151 | optional = false 152 | python-versions = ">=3.8" 153 | groups = ["main"] 154 | files = [ 155 | {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, 156 | {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, 157 | ] 158 | 159 | [[package]] 160 | name = "pluggy" 161 | version = "1.6.0" 162 | description = "plugin and hook calling mechanisms for python" 163 | optional = false 164 | python-versions = ">=3.9" 165 | groups = ["main"] 166 | files = [ 167 | {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, 168 | {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, 169 | ] 170 | 171 | [package.extras] 172 | dev = ["pre-commit", "tox"] 173 | testing = ["coverage", "pytest", "pytest-benchmark"] 174 | 175 | [[package]] 176 | name = "pydantic" 177 | version = "2.11.7" 178 | description = "Data validation using Python type hints" 179 | optional = false 180 | python-versions = ">=3.9" 181 | groups = ["main"] 182 | files = [ 183 | {file = "pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b"}, 184 | {file = "pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db"}, 185 | ] 186 | 187 | [package.dependencies] 188 | annotated-types = ">=0.6.0" 189 | pydantic-core = "2.33.2" 190 | typing-extensions = ">=4.12.2" 191 | typing-inspection = ">=0.4.0" 192 | 193 | [package.extras] 194 | email = ["email-validator (>=2.0.0)"] 195 | timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] 196 | 197 | [[package]] 198 | name = "pydantic-core" 199 | version = "2.33.2" 200 | description = "Core functionality for Pydantic validation and serialization" 201 | optional = false 202 | python-versions = ">=3.9" 203 | groups = ["main"] 204 | files = [ 205 | {file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"}, 206 | {file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"}, 207 | {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"}, 208 | {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"}, 209 | {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"}, 210 | {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"}, 211 | {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"}, 212 | {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"}, 213 | {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"}, 214 | {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"}, 215 | {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"}, 216 | {file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"}, 217 | {file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"}, 218 | {file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"}, 219 | {file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"}, 220 | {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"}, 221 | {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"}, 222 | {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"}, 223 | {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"}, 224 | {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"}, 225 | {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"}, 226 | {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"}, 227 | {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"}, 228 | {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"}, 229 | {file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"}, 230 | {file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"}, 231 | {file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"}, 232 | {file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"}, 233 | {file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"}, 234 | {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"}, 235 | {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"}, 236 | {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"}, 237 | {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"}, 238 | {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"}, 239 | {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"}, 240 | {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"}, 241 | {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"}, 242 | {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"}, 243 | {file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"}, 244 | {file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"}, 245 | {file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"}, 246 | {file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"}, 247 | {file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"}, 248 | {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"}, 249 | {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"}, 250 | {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"}, 251 | {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"}, 252 | {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"}, 253 | {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"}, 254 | {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"}, 255 | {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"}, 256 | {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"}, 257 | {file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"}, 258 | {file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"}, 259 | {file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"}, 260 | {file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"}, 261 | {file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"}, 262 | {file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"}, 263 | {file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"}, 264 | {file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"}, 265 | {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"}, 266 | {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"}, 267 | {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"}, 268 | {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"}, 269 | {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"}, 270 | {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"}, 271 | {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"}, 272 | {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"}, 273 | {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"}, 274 | {file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"}, 275 | {file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"}, 276 | {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"}, 277 | {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"}, 278 | {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"}, 279 | {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"}, 280 | {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"}, 281 | {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"}, 282 | {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"}, 283 | {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"}, 284 | {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"}, 285 | {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"}, 286 | {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"}, 287 | {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"}, 288 | {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"}, 289 | {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"}, 290 | {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"}, 291 | {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"}, 292 | {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"}, 293 | {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"}, 294 | {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"}, 295 | {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"}, 296 | {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"}, 297 | {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"}, 298 | {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"}, 299 | {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"}, 300 | {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"}, 301 | {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"}, 302 | {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"}, 303 | {file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"}, 304 | ] 305 | 306 | [package.dependencies] 307 | typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" 308 | 309 | [[package]] 310 | name = "pygments" 311 | version = "2.19.2" 312 | description = "Pygments is a syntax highlighting package written in Python." 313 | optional = false 314 | python-versions = ">=3.8" 315 | groups = ["main"] 316 | files = [ 317 | {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, 318 | {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, 319 | ] 320 | 321 | [package.extras] 322 | windows-terminal = ["colorama (>=0.4.6)"] 323 | 324 | [[package]] 325 | name = "pytest" 326 | version = "8.4.1" 327 | description = "pytest: simple powerful testing with Python" 328 | optional = false 329 | python-versions = ">=3.9" 330 | groups = ["main"] 331 | files = [ 332 | {file = "pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7"}, 333 | {file = "pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c"}, 334 | ] 335 | 336 | [package.dependencies] 337 | colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} 338 | iniconfig = ">=1" 339 | packaging = ">=20" 340 | pluggy = ">=1.5,<2" 341 | pygments = ">=2.7.2" 342 | 343 | [package.extras] 344 | dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] 345 | 346 | [[package]] 347 | name = "sniffio" 348 | version = "1.3.1" 349 | description = "Sniff out which async library your code is running under" 350 | optional = false 351 | python-versions = ">=3.7" 352 | groups = ["main"] 353 | files = [ 354 | {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, 355 | {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, 356 | ] 357 | 358 | [[package]] 359 | name = "typing-extensions" 360 | version = "4.14.1" 361 | description = "Backported and Experimental Type Hints for Python 3.9+" 362 | optional = false 363 | python-versions = ">=3.9" 364 | groups = ["main"] 365 | files = [ 366 | {file = "typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76"}, 367 | {file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"}, 368 | ] 369 | 370 | [[package]] 371 | name = "typing-inspection" 372 | version = "0.4.1" 373 | description = "Runtime typing introspection tools" 374 | optional = false 375 | python-versions = ">=3.9" 376 | groups = ["main"] 377 | files = [ 378 | {file = "typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51"}, 379 | {file = "typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"}, 380 | ] 381 | 382 | [package.dependencies] 383 | typing-extensions = ">=4.12.0" 384 | 385 | [metadata] 386 | lock-version = "2.1" 387 | python-versions = ">=3.13" 388 | content-hash = "72cc29468ce7bab5d39b9691aa218a35d9acbfc28e726a43fffd6bc1d9795854" 389 | --------------------------------------------------------------------------------