diff --git a/.gitignore b/.gitignore index 0bf616a..57abffb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +**/__pycache__/ +**/.speakeasy/temp/ +**/.speakeasy/logs/ .speakeasy/reports # Speakeasy .venv/ diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 7d1221a..dd20b0c 100644 --- a/.speakeasy/gen.lock +++ b/.speakeasy/gen.lock @@ -1,12 +1,12 @@ lockVersion: 2.0.0 id: 2d5dbf5a-62be-411a-9c7b-bc7b6dc79e13 management: - docChecksum: 6657dd3e876a909472f364dc1fe34d72 - docVersion: 0.0.0 - speakeasyVersion: 1.480.0 - generationVersion: 2.499.0 - releaseVersion: 0.10.0 - configChecksum: 2b2d2389ee9ff1be5cd354baf7c62739 + docChecksum: ea43ce77353d51bc50602313f3c257e4 + docVersion: 0.13.8 + speakeasyVersion: 1.575.4 + generationVersion: 2.648.7 + releaseVersion: 0.11.0 + configChecksum: a474303f61bae3346b5a40b8e004eeb9 repoURL: https://github.com/livepeer/livepeer-ai-python.git installationURL: https://github.com/livepeer/livepeer-ai-python.git published: true @@ -14,18 +14,18 @@ features: python: additionalDependencies: 1.0.0 constsAndDefaults: 1.0.5 - core: 5.10.7 + core: 5.19.4 defaultEnabledRetries: 0.2.0 envVarSecurityUsage: 0.3.2 - globalSecurity: 3.0.2 + globalSecurity: 3.0.3 globalSecurityCallbacks: 1.0.0 globalSecurityFlattening: 1.0.0 - globalServerURLs: 3.1.0 + globalServerURLs: 3.1.1 multipartFileContentType: 1.0.0 nameOverrides: 3.0.1 responseFormat: 1.0.1 retries: 3.0.2 - sdkHooks: 1.0.0 + sdkHooks: 1.1.0 unions: 3.0.4 uploadStreams: 1.0.0 generatedFiles: @@ -88,7 +88,7 @@ generatedFiles: - py.typed - pylintrc - pyproject.toml - - scripts/prepare-readme.py + - scripts/prepare_readme.py - scripts/publish.sh - src/livepeer_ai/__init__.py - src/livepeer_ai/_hooks/__init__.py @@ -98,6 +98,7 @@ generatedFiles: - src/livepeer_ai/basesdk.py - src/livepeer_ai/generate.py - src/livepeer_ai/httpclient.py + - src/livepeer_ai/models/__init__.py - src/livepeer_ai/models/components/__init__.py - src/livepeer_ai/models/components/apierror.py - src/livepeer_ai/models/components/audioresponse.py @@ -130,6 +131,9 @@ generatedFiles: - src/livepeer_ai/models/errors/__init__.py - src/livepeer_ai/models/errors/httperror.py - src/livepeer_ai/models/errors/httpvalidationerror.py + - src/livepeer_ai/models/errors/livepeererror.py + - src/livepeer_ai/models/errors/no_response_error.py + - src/livepeer_ai/models/errors/responsevalidationerror.py - src/livepeer_ai/models/errors/sdkerror.py - src/livepeer_ai/models/operations/__init__.py - src/livepeer_ai/models/operations/genaudiototext.py @@ -149,6 +153,7 @@ generatedFiles: - src/livepeer_ai/types/basemodel.py - src/livepeer_ai/utils/__init__.py - src/livepeer_ai/utils/annotations.py + - src/livepeer_ai/utils/datetimes.py - src/livepeer_ai/utils/enums.py - src/livepeer_ai/utils/eventstreaming.py - src/livepeer_ai/utils/forms.py @@ -169,7 +174,7 @@ examples: application/json: {"model_id": "", "loras": "", "prompt": "", "height": 576, "width": 1024, "guidance_scale": 7.5, "negative_prompt": "", "safety_check": true, "num_inference_steps": 50, "num_images_per_prompt": 1} responses: "200": - application/json: {"images": [{"url": "https://hateful-cruelty.name", "seed": 857392, "nsfw": true}]} + application/json: {"images": []} "400": application/json: {"detail": {"msg": ""}} "422": @@ -179,10 +184,10 @@ examples: genImageToImage: speakeasy-default-gen-image-to-image: requestBody: - multipart/form-data: {"prompt": "", "image": {"": "x-file: example.file"}, "model_id": "", "loras": "", "strength": 0.8, "guidance_scale": 7.5, "image_guidance_scale": 1.5, "negative_prompt": "", "safety_check": true, "num_inference_steps": 100, "num_images_per_prompt": 1} + multipart/form-data: {"prompt": "", "image": "x-file: example.file", "model_id": "", "loras": "", "strength": 0.8, "guidance_scale": 7.5, "image_guidance_scale": 1.5, "negative_prompt": "", "safety_check": true, "num_inference_steps": 100, "num_images_per_prompt": 1} responses: "200": - application/json: {"images": [{"url": "https://selfish-operating.name/", "seed": 976514, "nsfw": false}]} + application/json: {"images": []} "400": application/json: {"detail": {"msg": ""}} "422": @@ -192,10 +197,10 @@ examples: genImageToVideo: speakeasy-default-gen-image-to-video: requestBody: - multipart/form-data: {"image": {"": "x-file: example.file"}, "model_id": "", "height": 576, "width": 1024, "fps": 6, "motion_bucket_id": 127, "noise_aug_strength": 0.02, "safety_check": true, "num_inference_steps": 25} + multipart/form-data: {"image": "x-file: example.file", "model_id": "", "height": 576, "width": 1024, "fps": 6, "motion_bucket_id": 127, "noise_aug_strength": 0.02, "safety_check": true, "num_inference_steps": 25} responses: "200": - application/json: {"images": [{"url": "https://low-handover.name/", "seed": 87160, "nsfw": true}]} + application/json: {"images": []} "400": application/json: {"detail": {"msg": ""}} "422": @@ -205,10 +210,10 @@ examples: genUpscale: speakeasy-default-gen-upscale: requestBody: - multipart/form-data: {"prompt": "", "image": {"": "x-file: example.file"}, "model_id": "", "safety_check": true, "num_inference_steps": 75} + multipart/form-data: {"prompt": "", "image": "x-file: example.file", "model_id": "", "safety_check": true, "num_inference_steps": 75} responses: "200": - application/json: {"images": [{"url": "https://bogus-typewriter.net", "seed": 311567, "nsfw": false}]} + application/json: {"images": []} "400": application/json: {"detail": {"msg": ""}} "422": @@ -218,10 +223,10 @@ examples: genAudioToText: speakeasy-default-gen-audio-to-text: requestBody: - multipart/form-data: {"audio": {"": "x-file: example.file"}, "model_id": "", "return_timestamps": "true"} + multipart/form-data: {"audio": "x-file: example.file", "model_id": "", "return_timestamps": "true"} responses: "200": - application/json: {"text": "", "chunks": [{"timestamp": ["", ""], "text": ""}, {"timestamp": [], "text": ""}]} + application/json: {"text": "", "chunks": []} "400": application/json: {"detail": {"msg": ""}} "422": @@ -231,7 +236,7 @@ examples: genSegmentAnything2: speakeasy-default-gen-segment-anything2: requestBody: - multipart/form-data: {"image": {"": "x-file: example.file"}, "model_id": "", "multimask_output": true, "return_logits": true, "normalize_coords": true} + multipart/form-data: {"image": "x-file: example.file", "model_id": "", "multimask_output": true, "return_logits": true, "normalize_coords": true} responses: "200": application/json: {"masks": "", "scores": "", "logits": ""} @@ -244,10 +249,10 @@ examples: genLLM: speakeasy-default-gen-LLM: requestBody: - application/json: {"messages": [], "model": "", "temperature": 0.7, "max_tokens": 256, "top_p": 1, "top_k": -1, "stream": false} + application/json: {"messages": [{"role": "", "content": ""}], "model": "", "temperature": 0.7, "max_tokens": 256, "top_p": 1, "top_k": -1, "stream": false} responses: "200": - application/json: {"id": "", "model": "Expedition", "created": 755586, "usage": {"prompt_tokens": 348799, "completion_tokens": 332397, "total_tokens": 528534}, "choices": []} + application/json: {"id": "", "model": "Explorer", "created": 166063, "usage": {"prompt_tokens": 213097, "completion_tokens": 185693, "total_tokens": 530500}, "choices": []} "400": application/json: {"detail": {"msg": ""}} "422": @@ -257,7 +262,7 @@ examples: genImageToText: speakeasy-default-gen-image-to-text: requestBody: - multipart/form-data: {"image": {"": "x-file: example.file"}, "prompt": "", "model_id": ""} + multipart/form-data: {"image": "x-file: example.file", "prompt": "", "model_id": ""} responses: "200": application/json: {"text": ""} @@ -270,10 +275,10 @@ examples: genLiveVideoToVideo: speakeasy-default-gen-live-video-to-video: requestBody: - application/json: {"subscribe_url": "https://soulful-lava.org/", "publish_url": "https://vain-tabletop.biz", "control_url": "", "events_url": "", "model_id": ""} + application/json: {"subscribe_url": "https://soulful-finding.biz", "publish_url": "https://monumental-representation.biz/", "control_url": "", "events_url": "", "model_id": "", "gateway_request_id": "", "manifest_id": "", "stream_id": ""} responses: "200": - application/json: {"subscribe_url": "https://vain-kiss.name", "publish_url": "https://frail-duffel.com", "control_url": "", "events_url": ""} + application/json: {"subscribe_url": "https://any-expense.com/", "publish_url": "https://early-abacus.org", "control_url": "", "events_url": "", "request_id": "", "manifest_id": ""} "400": application/json: {"detail": {"msg": ""}} "422": @@ -286,12 +291,12 @@ examples: application/json: {"model_id": "", "text": "", "description": "A male speaker delivers a slightly expressive and animated speech with a moderate speed and pitch."} responses: "200": - application/json: {"audio": {"url": "https://accurate-parsnip.net/"}} + application/json: {"audio": {"url": "https://slushy-elevation.net/"}} "400": application/json: {"detail": {"msg": ""}} "422": application/json: {} "500": application/json: {"detail": {"msg": ""}} -examplesVersion: 1.0.0 +examplesVersion: 1.0.2 generatedTests: {} diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index 0dbd2d1..f819361 100644 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -4,22 +4,31 @@ generation: maintainOpenAPIOrder: true usageSnippets: optionalPropertyRendering: withExample + sdkInitStyle: constructor useClassNamesForArrayFields: true fixes: nameResolutionDec2023: true + nameResolutionFeb2025: false parameterOrderingFeb2024: true requestResponseComponentNamesFeb2024: true + securityFeb2025: false + sharedErrorComponentsApr2025: false auth: oAuth2ClientCredentialsEnabled: true oAuth2PasswordEnabled: false + tests: + generateTests: true + generateNewTests: false + skipResponseBodyAssertions: false python: - version: 0.10.0 + version: 0.11.0 additionalDependencies: dev: {} main: {} author: Livepeer authors: - Speakeasy + baseErrorName: LivepeerError clientServerStatusCodesAsErrors: true defaultErrorName: SDKError description: Python Client SDK for the Livepeer AI API. @@ -41,8 +50,11 @@ python: inputModelSuffix: input maxMethodParams: 4 methodArguments: require-security-and-request + moduleName: "" outputModelSuffix: output packageName: livepeer-ai projectUrls: {} + pytestFilterWarnings: [] + pytestTimeout: 0 responseFormat: envelope-http templateVersion: v2 diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index 3b25486..e91c17f 100644 --- a/.speakeasy/workflow.lock +++ b/.speakeasy/workflow.lock @@ -1,13 +1,13 @@ -speakeasyVersion: 1.480.0 +speakeasyVersion: 1.575.4 sources: livepeer_ai-OAS: sourceNamespace: livepeer-ai-oas - sourceRevisionDigest: sha256:0f47b792f474d38abc86f9276b065e4047dc61d6c0899a85a11008e48857db3a - sourceBlobDigest: sha256:7c0df39c1c5f0ffe580b63f5dc6cb0f81181f5361a80f63f41314cf81d0f3bf4 + sourceRevisionDigest: sha256:c54048bcd009d6c8e90eb870fda71dec7c5581a688d17caecc64b48b0aa067e5 + sourceBlobDigest: sha256:e4fc371161f14a6071fc4c6856fc7bae486e8a4676f72280212bc1856dd396b8 tags: - latest - - speakeasy-sdk-regen-1736900210 - - 0.0.0 + - speakeasy-sdk-regen-1739751486 + - 0.13.8 targets: livepeer-ai: source: livepeer_ai-OAS @@ -17,10 +17,10 @@ targets: livepeer-ai-python: source: livepeer_ai-OAS sourceNamespace: livepeer-ai-oas - sourceRevisionDigest: sha256:0f47b792f474d38abc86f9276b065e4047dc61d6c0899a85a11008e48857db3a - sourceBlobDigest: sha256:7c0df39c1c5f0ffe580b63f5dc6cb0f81181f5361a80f63f41314cf81d0f3bf4 + sourceRevisionDigest: sha256:c54048bcd009d6c8e90eb870fda71dec7c5581a688d17caecc64b48b0aa067e5 + sourceBlobDigest: sha256:e4fc371161f14a6071fc4c6856fc7bae486e8a4676f72280212bc1856dd396b8 codeSamplesNamespace: code-samples-python-livepeer-python - codeSamplesRevisionDigest: sha256:c8ec9be643b93d4a2f53b416df7270cf0cdb44cee849f5de6d2501edef3d2fa9 + codeSamplesRevisionDigest: sha256:ca1fc2cc6a53b17accde367f06c45f433585476dea501153cd1b2fc122d1d92f workflow: workflowVersion: 1.0.0 speakeasyVersion: latest diff --git a/README.md b/README.md index c1934a6..9ef0940 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,37 @@ pip install livepeer-ai ```bash poetry add livepeer-ai ``` + +### Shell and script usage with `uv` + +You can use this SDK in a Python shell with [uv](https://docs.astral.sh/uv/) and the `uvx` command that comes with it like so: + +```shell +uvx --from livepeer-ai python +``` + +It's also possible to write a standalone Python script without needing to set up a whole project like so: + +```python +#!/usr/bin/env -S uv run --script +# /// script +# requires-python = ">=3.9" +# dependencies = [ +# "livepeer-ai", +# ] +# /// + +from livepeer_ai import Livepeer + +sdk = Livepeer( + # SDK arguments +) + +# Rest of script here... +``` + +Once that is saved to a file, you can run it with `uv run script.py` where +`script.py` can be replaced with the actual file name. @@ -55,21 +86,13 @@ Generally, the SDK will work well with most IDEs out of the box. However, when u # Synchronous Example from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: res = livepeer.generate.text_to_image(request={ "prompt": "", - "model_id": "", - "loras": "", - "height": 576, - "width": 1024, - "guidance_scale": 7.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 50, - "num_images_per_prompt": 1, }) assert res.image_response is not None @@ -87,21 +110,13 @@ import asyncio from livepeer_ai import Livepeer async def main(): + async with Livepeer( http_bearer="", ) as livepeer: res = await livepeer.generate.text_to_image_async(request={ "prompt": "", - "model_id": "", - "loras": "", - "height": 576, - "width": 1024, - "guidance_scale": 7.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 50, - "num_images_per_prompt": 1, }) assert res.image_response is not None @@ -149,6 +164,7 @@ Certain SDK methods accept file objects as part of a request body or multi-part ```python from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: @@ -159,15 +175,6 @@ with Livepeer( "file_name": "example.file", "content": open("example.file", "rb"), }, - "model_id": "", - "loras": "", - "strength": 0.8, - "guidance_scale": 7.5, - "image_guidance_scale": 1.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 100, - "num_images_per_prompt": 1, }) assert res.image_response is not None @@ -188,21 +195,13 @@ To change the default retry strategy for a single API call, simply provide a `Re from livepeer_ai import Livepeer from livepeer_ai.utils import BackoffStrategy, RetryConfig + with Livepeer( http_bearer="", ) as livepeer: res = livepeer.generate.text_to_image(request={ "prompt": "", - "model_id": "", - "loras": "", - "height": 576, - "width": 1024, - "guidance_scale": 7.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 50, - "num_images_per_prompt": 1, }, RetryConfig("backoff", BackoffStrategy(1, 50, 1.1, 100), False)) @@ -218,6 +217,7 @@ If you'd like to override the default retry strategy for all operations that sup from livepeer_ai import Livepeer from livepeer_ai.utils import BackoffStrategy, RetryConfig + with Livepeer( retry_config=RetryConfig("backoff", BackoffStrategy(1, 50, 1.1, 100), False), http_bearer="", @@ -225,15 +225,6 @@ with Livepeer( res = livepeer.generate.text_to_image(request={ "prompt": "", - "model_id": "", - "loras": "", - "height": 576, - "width": 1024, - "guidance_scale": 7.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 50, - "num_images_per_prompt": 1, }) assert res.image_response is not None @@ -247,32 +238,23 @@ with Livepeer( ## Error Handling -Handling errors in this SDK should largely match your expectations. All operations return a response object or raise an exception. - -By default, an API error will raise a errors.SDKError exception, which has the following properties: +[`LivepeerError`](./src/livepeer_ai/models/errors/livepeererror.py) is the base class for all HTTP error responses. It has the following properties: -| Property | Type | Description | -|-----------------|------------------|-----------------------| -| `.status_code` | *int* | The HTTP status code | -| `.message` | *str* | The error message | -| `.raw_response` | *httpx.Response* | The raw HTTP response | -| `.body` | *str* | The response content | - -When custom error responses are specified for an operation, the SDK may also raise their associated exceptions. You can refer to respective *Errors* tables in SDK docs for more details on possible exception types for each operation. For example, the `text_to_image_async` method may raise the following exceptions: - -| Error Type | Status Code | Content Type | -| -------------------------- | ----------- | ---------------- | -| errors.HTTPError | 400, 401 | application/json | -| errors.HTTPValidationError | 422 | application/json | -| errors.HTTPError | 500 | application/json | -| errors.SDKError | 4XX, 5XX | \*/\* | +| Property | Type | Description | +| ------------------ | ---------------- | --------------------------------------------------------------------------------------- | +| `err.message` | `str` | Error message | +| `err.status_code` | `int` | HTTP response status code eg `404` | +| `err.headers` | `httpx.Headers` | HTTP response headers | +| `err.body` | `str` | HTTP body. Can be empty string if no body is returned. | +| `err.raw_response` | `httpx.Response` | Raw HTTP response | +| `err.data` | | Optional. Some errors may contain structured data. [See Error Classes](#error-classes). | ### Example - ```python from livepeer_ai import Livepeer from livepeer_ai.models import errors + with Livepeer( http_bearer="", ) as livepeer: @@ -281,15 +263,6 @@ with Livepeer( res = livepeer.generate.text_to_image(request={ "prompt": "", - "model_id": "", - "loras": "", - "height": 576, - "width": 1024, - "guidance_scale": 7.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 50, - "num_images_per_prompt": 1, }) assert res.image_response is not None @@ -297,19 +270,40 @@ with Livepeer( # Handle response print(res.image_response) - except errors.HTTPError as e: - # handle e.data: errors.HTTPErrorData - raise(e) - except errors.HTTPValidationError as e: - # handle e.data: errors.HTTPValidationErrorData - raise(e) - except errors.HTTPError as e: - # handle e.data: errors.HTTPErrorData - raise(e) - except errors.SDKError as e: - # handle exception - raise(e) + + except errors.LivepeerError as e: + # The base class for HTTP error responses + print(e.message) + print(e.status_code) + print(e.body) + print(e.headers) + print(e.raw_response) + + # Depending on the method different errors may be thrown + if isinstance(e, errors.HTTPError): + print(e.data.detail) # components.APIError ``` + +### Error Classes +**Primary errors:** +* [`LivepeerError`](./src/livepeer_ai/models/errors/livepeererror.py): The base class for HTTP error responses. + * [`HTTPError`](./src/livepeer_ai/models/errors/httperror.py): HTTP error response model. + * [`HTTPValidationError`](./src/livepeer_ai/models/errors/httpvalidationerror.py): Validation Error. Status code `422`. + +
Less common errors (5) + +
+ +**Network errors:** +* [`httpx.RequestError`](https://www.python-httpx.org/exceptions/#httpx.RequestError): Base class for request errors. + * [`httpx.ConnectError`](https://www.python-httpx.org/exceptions/#httpx.ConnectError): HTTP client was unable to make a request to a server. + * [`httpx.TimeoutException`](https://www.python-httpx.org/exceptions/#httpx.TimeoutException): HTTP request timed out. + + +**Inherit from [`LivepeerError`](./src/livepeer_ai/models/errors/livepeererror.py)**: +* [`ResponseValidationError`](./src/livepeer_ai/models/errors/responsevalidationerror.py): Type mismatch between the response data and the expected Pydantic model. Provides access to the Pydantic validation error via the `cause` attribute. + +
@@ -319,16 +313,17 @@ with Livepeer( You can override the default server globally by passing a server index to the `server_idx: int` optional parameter when initializing the SDK client instance. The selected server will then be used as the default on the operations that use it. This table lists the indexes associated with the available servers: -| # | Server | -| --- | ------------------------------------------- | -| 0 | `https://dream-gateway.livepeer.cloud` | -| 1 | `https://livepeer.studio/api/beta/generate` | +| # | Server | Description | +| --- | ------------------------------------------- | -------------------------------- | +| 0 | `https://dream-gateway.livepeer.cloud` | Livepeer Cloud Community Gateway | +| 1 | `https://livepeer.studio/api/beta/generate` | Livepeer Studio Gateway | #### Example ```python from livepeer_ai import Livepeer + with Livepeer( server_idx=1, http_bearer="", @@ -336,15 +331,6 @@ with Livepeer( res = livepeer.generate.text_to_image(request={ "prompt": "", - "model_id": "", - "loras": "", - "height": 576, - "width": 1024, - "guidance_scale": 7.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 50, - "num_images_per_prompt": 1, }) assert res.image_response is not None @@ -360,22 +346,14 @@ The default server can also be overridden globally by passing a URL to the `serv ```python from livepeer_ai import Livepeer + with Livepeer( - server_url="https://dream-gateway.livepeer.cloud", + server_url="https://livepeer.studio/api/beta/generate", http_bearer="", ) as livepeer: res = livepeer.generate.text_to_image(request={ "prompt": "", - "model_id": "", - "loras": "", - "height": 576, - "width": 1024, - "guidance_scale": 7.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 50, - "num_images_per_prompt": 1, }) assert res.image_response is not None @@ -482,21 +460,13 @@ To authenticate with the API the `http_bearer` parameter must be set when initia ```python from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: res = livepeer.generate.text_to_image(request={ "prompt": "", - "model_id": "", - "loras": "", - "height": 576, - "width": 1024, - "guidance_scale": 7.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 50, - "num_images_per_prompt": 1, }) assert res.image_response is not None @@ -517,6 +487,7 @@ The `Livepeer` class implements the context manager protocol and registers a fin ```python from livepeer_ai import Livepeer def main(): + with Livepeer( http_bearer="", ) as livepeer: @@ -525,6 +496,7 @@ def main(): # Or when using async: async def amain(): + async with Livepeer( http_bearer="", ) as livepeer: diff --git a/RELEASES.md b/RELEASES.md index 60caa97..c89b53e 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -138,4 +138,14 @@ Based on: ### Generated - [python v0.10.0] . ### Releases -- [PyPI v0.10.0] https://pypi.org/project/livepeer-ai/0.10.0 - . \ No newline at end of file +- [PyPI v0.10.0] https://pypi.org/project/livepeer-ai/0.10.0 - . + +## 2025-07-04 00:19:41 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.575.4 (2.648.7) https://github.com/speakeasy-api/speakeasy +### Generated +- [python v0.11.0] . +### Releases +- [PyPI v0.11.0] https://pypi.org/project/livepeer-ai/0.11.0 - . \ No newline at end of file diff --git a/USAGE.md b/USAGE.md index b791757..8d7ec8b 100644 --- a/USAGE.md +++ b/USAGE.md @@ -3,21 +3,13 @@ # Synchronous Example from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: res = livepeer.generate.text_to_image(request={ "prompt": "", - "model_id": "", - "loras": "", - "height": 576, - "width": 1024, - "guidance_scale": 7.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 50, - "num_images_per_prompt": 1, }) assert res.image_response is not None @@ -35,21 +27,13 @@ import asyncio from livepeer_ai import Livepeer async def main(): + async with Livepeer( http_bearer="", ) as livepeer: res = await livepeer.generate.text_to_image_async(request={ "prompt": "", - "model_id": "", - "loras": "", - "height": 576, - "width": 1024, - "guidance_scale": 7.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 50, - "num_images_per_prompt": 1, }) assert res.image_response is not None diff --git a/codeSamples.yaml b/codeSamples.yaml index 261c4e1..7161c11 100644 --- a/codeSamples.yaml +++ b/codeSamples.yaml @@ -11,6 +11,7 @@ actions: source: |- from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: @@ -20,8 +21,6 @@ actions: "file_name": "example.file", "content": open("example.file", "rb"), }, - "model_id": "", - "return_timestamps": "true", }) assert res.text_response is not None @@ -36,6 +35,7 @@ actions: source: |- from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: @@ -46,15 +46,6 @@ actions: "file_name": "example.file", "content": open("example.file", "rb"), }, - "model_id": "", - "loras": "", - "strength": 0.8, - "guidance_scale": 7.5, - "image_guidance_scale": 1.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 100, - "num_images_per_prompt": 1, }) assert res.image_response is not None @@ -69,6 +60,7 @@ actions: source: |- from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: @@ -78,8 +70,6 @@ actions: "file_name": "example.file", "content": open("example.file", "rb"), }, - "prompt": "", - "model_id": "", }) assert res.image_to_text_response is not None @@ -94,6 +84,7 @@ actions: source: |- from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: @@ -103,14 +94,6 @@ actions: "file_name": "example.file", "content": open("example.file", "rb"), }, - "model_id": "", - "height": 576, - "width": 1024, - "fps": 6, - "motion_bucket_id": 127, - "noise_aug_strength": 0.02, - "safety_check": True, - "num_inference_steps": 25, }) assert res.video_response is not None @@ -125,16 +108,14 @@ actions: source: |- from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: res = livepeer.generate.live_video_to_video(request={ - "subscribe_url": "https://soulful-lava.org/", - "publish_url": "https://vain-tabletop.biz", - "control_url": "", - "events_url": "", - "model_id": "", + "subscribe_url": "https://soulful-finding.biz", + "publish_url": "https://monumental-representation.biz/", }) assert res.live_video_to_video_response is not None @@ -149,20 +130,18 @@ actions: source: |- from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: res = livepeer.generate.llm(request={ "messages": [ - + { + "role": "", + "content": "", + }, ], - "model": "", - "temperature": 0.7, - "max_tokens": 256, - "top_p": 1, - "top_k": -1, - "stream": False, }) assert res.llm_response is not None @@ -177,6 +156,7 @@ actions: source: |- from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: @@ -186,10 +166,6 @@ actions: "file_name": "example.file", "content": open("example.file", "rb"), }, - "model_id": "", - "multimask_output": True, - "return_logits": True, - "normalize_coords": True, }) assert res.masks_response is not None @@ -204,21 +180,13 @@ actions: source: |- from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: res = livepeer.generate.text_to_image(request={ - "model_id": "", - "loras": "", "prompt": "", - "height": 576, - "width": 1024, - "guidance_scale": 7.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 50, - "num_images_per_prompt": 1, }) assert res.image_response is not None @@ -233,15 +201,12 @@ actions: source: |- from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: - res = livepeer.generate.text_to_speech(request={ - "model_id": "", - "text": "", - "description": "A male speaker delivers a slightly expressive and animated speech with a moderate speed and pitch.", - }) + res = livepeer.generate.text_to_speech(request={}) assert res.audio_response is not None @@ -255,6 +220,7 @@ actions: source: |- from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: @@ -265,9 +231,6 @@ actions: "file_name": "example.file", "content": open("example.file", "rb"), }, - "model_id": "", - "safety_check": True, - "num_inference_steps": 75, }) assert res.image_response is not None diff --git a/docs/models/components/livevideotovideoparams.md b/docs/models/components/livevideotovideoparams.md index 00cdce2..427a574 100644 --- a/docs/models/components/livevideotovideoparams.md +++ b/docs/models/components/livevideotovideoparams.md @@ -10,4 +10,7 @@ | `control_url` | *Optional[str]* | :heavy_minus_sign: | URL for subscribing via Trickle protocol for updates in the live video-to-video generation params. | | `events_url` | *Optional[str]* | :heavy_minus_sign: | URL for publishing events via Trickle protocol for pipeline status and logs. | | `model_id` | *Optional[str]* | :heavy_minus_sign: | Name of the pipeline to run in the live video to video job. Notice that this is named model_id for consistency with other routes, but it does not refer to a Hugging Face model ID. The exact model(s) depends on the pipeline implementation and might be configurable via the `params` argument. | -| `params` | [Optional[components.Params]](../../models/components/params.md) | :heavy_minus_sign: | Initial parameters for the pipeline. | \ No newline at end of file +| `params` | [Optional[components.Params]](../../models/components/params.md) | :heavy_minus_sign: | Initial parameters for the pipeline. | +| `gateway_request_id` | *Optional[str]* | :heavy_minus_sign: | The ID of the Gateway request (for logging purposes). | +| `manifest_id` | *Optional[str]* | :heavy_minus_sign: | The manifest ID from the orchestrator (for logging purposes). | +| `stream_id` | *Optional[str]* | :heavy_minus_sign: | The Stream ID (for logging purposes). | \ No newline at end of file diff --git a/docs/models/components/livevideotovideoresponse.md b/docs/models/components/livevideotovideoresponse.md index be6f816..a0a3620 100644 --- a/docs/models/components/livevideotovideoresponse.md +++ b/docs/models/components/livevideotovideoresponse.md @@ -10,4 +10,6 @@ Response model for live video-to-video generation. | `subscribe_url` | *str* | :heavy_check_mark: | Source URL of the incoming stream to subscribe to | | `publish_url` | *str* | :heavy_check_mark: | Destination URL of the outgoing stream to publish to | | `control_url` | *Optional[str]* | :heavy_minus_sign: | URL for updating the live video-to-video generation | -| `events_url` | *Optional[str]* | :heavy_minus_sign: | URL for subscribing to events for pipeline status and logs | \ No newline at end of file +| `events_url` | *Optional[str]* | :heavy_minus_sign: | URL for subscribing to events for pipeline status and logs | +| `request_id` | *Optional[str]* | :heavy_minus_sign: | The ID generated for this request | +| `manifest_id` | *Optional[str]* | :heavy_minus_sign: | Orchestrator manifest ID for this request | \ No newline at end of file diff --git a/docs/models/components/texttoimageparams.md b/docs/models/components/texttoimageparams.md index 7abc04d..fb3111c 100644 --- a/docs/models/components/texttoimageparams.md +++ b/docs/models/components/texttoimageparams.md @@ -5,9 +5,9 @@ | Field | Type | Required | Description | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `prompt` | *str* | :heavy_check_mark: | Text prompt(s) to guide image generation. Separate multiple prompts with '\|' if supported by the model. | | `model_id` | *Optional[str]* | :heavy_minus_sign: | Hugging Face model ID used for image generation. | | `loras` | *Optional[str]* | :heavy_minus_sign: | A LoRA (Low-Rank Adaptation) model and its corresponding weight for image generation. Example: { "latent-consistency/lcm-lora-sdxl": 1.0, "nerijs/pixel-art-xl": 1.2}. | +| `prompt` | *str* | :heavy_check_mark: | Text prompt(s) to guide image generation. Separate multiple prompts with '\|' if supported by the model. | | `height` | *Optional[int]* | :heavy_minus_sign: | The height in pixels of the generated image. | | `width` | *Optional[int]* | :heavy_minus_sign: | The width in pixels of the generated image. | | `guidance_scale` | *Optional[float]* | :heavy_minus_sign: | Encourages model to generate images closely linked to the text prompt (higher values may reduce image quality). | diff --git a/docs/sdks/generate/README.md b/docs/sdks/generate/README.md index 787807d..582a96a 100644 --- a/docs/sdks/generate/README.md +++ b/docs/sdks/generate/README.md @@ -25,21 +25,13 @@ Generate images from text prompts. ```python from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: res = livepeer.generate.text_to_image(request={ "prompt": "", - "model_id": "", - "loras": "", - "height": 576, - "width": 1024, - "guidance_scale": 7.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 50, - "num_images_per_prompt": 1, }) assert res.image_response is not None @@ -78,6 +70,7 @@ Apply image transformations to a provided image. ```python from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: @@ -88,15 +81,6 @@ with Livepeer( "file_name": "example.file", "content": open("example.file", "rb"), }, - "model_id": "", - "loras": "", - "strength": 0.8, - "guidance_scale": 7.5, - "image_guidance_scale": 1.5, - "negative_prompt": "", - "safety_check": True, - "num_inference_steps": 100, - "num_images_per_prompt": 1, }) assert res.image_response is not None @@ -135,6 +119,7 @@ Generate a video from a provided image. ```python from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: @@ -144,14 +129,6 @@ with Livepeer( "file_name": "example.file", "content": open("example.file", "rb"), }, - "model_id": "", - "height": 576, - "width": 1024, - "fps": 6, - "motion_bucket_id": 127, - "noise_aug_strength": 0.02, - "safety_check": True, - "num_inference_steps": 25, }) assert res.video_response is not None @@ -190,6 +167,7 @@ Upscale an image by increasing its resolution. ```python from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: @@ -200,9 +178,6 @@ with Livepeer( "file_name": "example.file", "content": open("example.file", "rb"), }, - "model_id": "", - "safety_check": True, - "num_inference_steps": 75, }) assert res.image_response is not None @@ -241,6 +216,7 @@ Transcribe audio files to text. ```python from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: @@ -250,8 +226,6 @@ with Livepeer( "file_name": "example.file", "content": open("example.file", "rb"), }, - "model_id": "", - "return_timestamps": "true", }) assert res.text_response is not None @@ -290,6 +264,7 @@ Segment objects in an image. ```python from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: @@ -299,10 +274,6 @@ with Livepeer( "file_name": "example.file", "content": open("example.file", "rb"), }, - "model_id": "", - "multimask_output": True, - "return_logits": True, - "normalize_coords": True, }) assert res.masks_response is not None @@ -341,20 +312,18 @@ Generate text using a language model. ```python from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: res = livepeer.generate.llm(request={ "messages": [ - + { + "role": "", + "content": "", + }, ], - "model": "", - "temperature": 0.7, - "max_tokens": 256, - "top_p": 1, - "top_k": -1, - "stream": False, }) assert res.llm_response is not None @@ -393,6 +362,7 @@ Transform image files to text. ```python from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: @@ -402,8 +372,6 @@ with Livepeer( "file_name": "example.file", "content": open("example.file", "rb"), }, - "prompt": "", - "model_id": "", }) assert res.image_to_text_response is not None @@ -442,16 +410,14 @@ Apply transformations to a live video streamed to the returned endpoints. ```python from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: res = livepeer.generate.live_video_to_video(request={ - "subscribe_url": "https://soulful-lava.org/", - "publish_url": "https://vain-tabletop.biz", - "control_url": "", - "events_url": "", - "model_id": "", + "subscribe_url": "https://soulful-finding.biz", + "publish_url": "https://monumental-representation.biz/", }) assert res.live_video_to_video_response is not None @@ -490,15 +456,12 @@ Generate a text-to-speech audio file based on the provided text input and speake ```python from livepeer_ai import Livepeer + with Livepeer( http_bearer="", ) as livepeer: - res = livepeer.generate.text_to_speech(request={ - "model_id": "", - "text": "", - "description": "A male speaker delivers a slightly expressive and animated speech with a moderate speed and pitch.", - }) + res = livepeer.generate.text_to_speech(request={}) assert res.audio_response is not None diff --git a/poetry.lock b/poetry.lock index 431e79a..5e4c329 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "annotated-types" @@ -32,7 +32,7 @@ typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\""] trio = ["trio (>=0.23)"] [[package]] @@ -91,21 +91,6 @@ files = [ graph = ["objgraph (>=1.7.2)"] profile = ["gprof2dot (>=2022.7.29)"] -[[package]] -name = "eval-type-backport" -version = "0.2.0" -description = "Like `typing._eval_type`, but lets older Python versions use newer typing features." -optional = false -python-versions = ">=3.8" -groups = ["main"] -files = [ - {file = "eval_type_backport-0.2.0-py3-none-any.whl", hash = "sha256:ac2f73d30d40c5a30a80b8739a789d6bb5e49fdffa66d7912667e2015d9c9933"}, - {file = "eval_type_backport-0.2.0.tar.gz", hash = "sha256:68796cfbc7371ebf923f03bdf7bef415f3ec098aeced24e054b253a0e78f7b37"}, -] - -[package.extras] -tests = ["pytest"] - [[package]] name = "exceptiongroup" version = "1.2.2" @@ -124,37 +109,37 @@ test = ["pytest (>=6)"] [[package]] name = "h11" -version = "0.14.0" +version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["main"] files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, ] [[package]] name = "httpcore" -version = "1.0.5" +version = "1.0.9" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, - {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, ] [package.dependencies] certifi = "*" -h11 = ">=0.13,<0.15" +h11 = ">=0.16" [package.extras] asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.26.0)"] +trio = ["trio (>=0.22.0,<1.0)"] [[package]] name = "httpx" @@ -175,7 +160,7 @@ httpcore = "==1.*" idna = "*" [package.extras] -brotli = ["brotli", "brotlicffi"] +brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] @@ -222,50 +207,44 @@ files = [ [[package]] name = "mypy" -version = "1.14.1" +version = "1.15.0" description = "Optional static typing for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "mypy-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52686e37cf13d559f668aa398dd7ddf1f92c5d613e4f8cb262be2fb4fedb0fcb"}, - {file = "mypy-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fb545ca340537d4b45d3eecdb3def05e913299ca72c290326be19b3804b39c0"}, - {file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90716d8b2d1f4cd503309788e51366f07c56635a3309b0f6a32547eaaa36a64d"}, - {file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae753f5c9fef278bcf12e1a564351764f2a6da579d4a81347e1d5a15819997b"}, - {file = "mypy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0fe0f5feaafcb04505bcf439e991c6d8f1bf8b15f12b05feeed96e9e7bf1427"}, - {file = "mypy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d54bd85b925e501c555a3227f3ec0cfc54ee8b6930bd6141ec872d1c572f81f"}, - {file = "mypy-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f995e511de847791c3b11ed90084a7a0aafdc074ab88c5a9711622fe4751138c"}, - {file = "mypy-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d64169ec3b8461311f8ce2fd2eb5d33e2d0f2c7b49116259c51d0d96edee48d1"}, - {file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba24549de7b89b6381b91fbc068d798192b1b5201987070319889e93038967a8"}, - {file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:183cf0a45457d28ff9d758730cd0210419ac27d4d3f285beda038c9083363b1f"}, - {file = "mypy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f2a0ecc86378f45347f586e4163d1769dd81c5a223d577fe351f26b179e148b1"}, - {file = "mypy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:ad3301ebebec9e8ee7135d8e3109ca76c23752bac1e717bc84cd3836b4bf3eae"}, - {file = "mypy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30ff5ef8519bbc2e18b3b54521ec319513a26f1bba19a7582e7b1f58a6e69f14"}, - {file = "mypy-1.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb9f255c18052343c70234907e2e532bc7e55a62565d64536dbc7706a20b78b9"}, - {file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b4e3413e0bddea671012b063e27591b953d653209e7a4fa5e48759cda77ca11"}, - {file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:553c293b1fbdebb6c3c4030589dab9fafb6dfa768995a453d8a5d3b23784af2e"}, - {file = "mypy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fad79bfe3b65fe6a1efaed97b445c3d37f7be9fdc348bdb2d7cac75579607c89"}, - {file = "mypy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fa2220e54d2946e94ab6dbb3ba0a992795bd68b16dc852db33028df2b00191b"}, - {file = "mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255"}, - {file = "mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34"}, - {file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a"}, - {file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4b19b03fdf54f3c5b2fa474c56b4c13c9dbfb9a2db4370ede7ec11a2c5927d9"}, - {file = "mypy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c911fde686394753fff899c409fd4e16e9b294c24bfd5e1ea4675deae1ac6fd"}, - {file = "mypy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8b21525cb51671219f5307be85f7e646a153e5acc656e5cebf64bfa076c50107"}, - {file = "mypy-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7084fb8f1128c76cd9cf68fe5971b37072598e7c31b2f9f95586b65c741a9d31"}, - {file = "mypy-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8f845a00b4f420f693f870eaee5f3e2692fa84cc8514496114649cfa8fd5e2c6"}, - {file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44bf464499f0e3a2d14d58b54674dee25c031703b2ffc35064bd0df2e0fac319"}, - {file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c99f27732c0b7dc847adb21c9d47ce57eb48fa33a17bc6d7d5c5e9f9e7ae5bac"}, - {file = "mypy-1.14.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:bce23c7377b43602baa0bd22ea3265c49b9ff0b76eb315d6c34721af4cdf1d9b"}, - {file = "mypy-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:8edc07eeade7ebc771ff9cf6b211b9a7d93687ff892150cb5692e4f4272b0837"}, - {file = "mypy-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3888a1816d69f7ab92092f785a462944b3ca16d7c470d564165fe703b0970c35"}, - {file = "mypy-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46c756a444117c43ee984bd055db99e498bc613a70bbbc120272bd13ca579fbc"}, - {file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:27fc248022907e72abfd8e22ab1f10e903915ff69961174784a3900a8cba9ad9"}, - {file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:499d6a72fb7e5de92218db961f1a66d5f11783f9ae549d214617edab5d4dbdbb"}, - {file = "mypy-1.14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57961db9795eb566dc1d1b4e9139ebc4c6b0cb6e7254ecde69d1552bf7613f60"}, - {file = "mypy-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:07ba89fdcc9451f2ebb02853deb6aaaa3d2239a236669a63ab3801bbf923ef5c"}, - {file = "mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1"}, - {file = "mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6"}, + {file = "mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13"}, + {file = "mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559"}, + {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b"}, + {file = "mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3"}, + {file = "mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b"}, + {file = "mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828"}, + {file = "mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f"}, + {file = "mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5"}, + {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e"}, + {file = "mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c"}, + {file = "mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f"}, + {file = "mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f"}, + {file = "mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd"}, + {file = "mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f"}, + {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464"}, + {file = "mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee"}, + {file = "mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e"}, + {file = "mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22"}, + {file = "mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445"}, + {file = "mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d"}, + {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5"}, + {file = "mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036"}, + {file = "mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357"}, + {file = "mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf"}, + {file = "mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078"}, + {file = "mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba"}, + {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5"}, + {file = "mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b"}, + {file = "mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2"}, + {file = "mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980"}, + {file = "mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e"}, + {file = "mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43"}, ] [package.dependencies] @@ -286,7 +265,7 @@ version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" -groups = ["main", "dev"] +groups = ["dev"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, @@ -311,133 +290,133 @@ type = ["mypy (>=1.8)"] [[package]] name = "pydantic" -version = "2.10.3" +version = "2.11.7" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d"}, - {file = "pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9"}, + {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.27.1" +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"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] [[package]] name = "pydantic-core" -version = "2.27.1" +version = "2.33.2" description = "Core functionality for Pydantic validation and serialization" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a"}, - {file = "pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08"}, - {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6"}, - {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807"}, - {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c"}, - {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206"}, - {file = "pydantic_core-2.27.1-cp310-none-win32.whl", hash = "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c"}, - {file = "pydantic_core-2.27.1-cp310-none-win_amd64.whl", hash = "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17"}, - {file = "pydantic_core-2.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8"}, - {file = "pydantic_core-2.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025"}, - {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e"}, - {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919"}, - {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c"}, - {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc"}, - {file = "pydantic_core-2.27.1-cp311-none-win32.whl", hash = "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9"}, - {file = "pydantic_core-2.27.1-cp311-none-win_amd64.whl", hash = "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5"}, - {file = "pydantic_core-2.27.1-cp311-none-win_arm64.whl", hash = "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89"}, - {file = "pydantic_core-2.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f"}, - {file = "pydantic_core-2.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35"}, - {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089"}, - {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381"}, - {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb"}, - {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae"}, - {file = "pydantic_core-2.27.1-cp312-none-win32.whl", hash = "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c"}, - {file = "pydantic_core-2.27.1-cp312-none-win_amd64.whl", hash = "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16"}, - {file = "pydantic_core-2.27.1-cp312-none-win_arm64.whl", hash = "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e"}, - {file = "pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073"}, - {file = "pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51"}, - {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a"}, - {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc"}, - {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960"}, - {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23"}, - {file = "pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05"}, - {file = "pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337"}, - {file = "pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5"}, - {file = "pydantic_core-2.27.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62"}, - {file = "pydantic_core-2.27.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78"}, - {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f"}, - {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36"}, - {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a"}, - {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b"}, - {file = "pydantic_core-2.27.1-cp38-none-win32.whl", hash = "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618"}, - {file = "pydantic_core-2.27.1-cp38-none-win_amd64.whl", hash = "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4"}, - {file = "pydantic_core-2.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967"}, - {file = "pydantic_core-2.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e"}, - {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792"}, - {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01"}, - {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9"}, - {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131"}, - {file = "pydantic_core-2.27.1-cp39-none-win32.whl", hash = "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3"}, - {file = "pydantic_core-2.27.1-cp39-none-win_amd64.whl", hash = "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f"}, - {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2"}, - {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840"}, - {file = "pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235"}, + {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] @@ -461,7 +440,7 @@ colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\" and python_version < \"3.12\""}, + {version = ">=0.3.6", markers = "python_version == \"3.11\""}, ] isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" mccabe = ">=0.6,<0.8" @@ -474,33 +453,6 @@ typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\"" spelling = ["pyenchant (>=3.2,<4.0)"] testutils = ["gitpython (>3)"] -[[package]] -name = "python-dateutil" -version = "2.8.2" -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.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, -] - -[package.dependencies] -six = ">=1.5" - -[[package]] -name = "six" -version = "1.16.0" -description = "Python 2 and 3 compatibility utilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -groups = ["main"] -files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, -] - [[package]] name = "sniffio" version = "1.3.1" @@ -538,18 +490,6 @@ files = [ {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, ] -[[package]] -name = "types-python-dateutil" -version = "2.9.0.20240821" -description = "Typing stubs for python-dateutil" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "types-python-dateutil-2.9.0.20240821.tar.gz", hash = "sha256:9649d1dcb6fef1046fb18bebe9ea2aa0028b160918518c34589a46045f6ebd98"}, - {file = "types_python_dateutil-2.9.0.20240821-py3-none-any.whl", hash = "sha256:f5889fcb4e63ed4aaa379b44f93c32593d50b9a94c9a60a0c854d8cc3511cd57"}, -] - [[package]] name = "typing-extensions" version = "4.12.2" @@ -563,22 +503,21 @@ files = [ ] [[package]] -name = "typing-inspect" -version = "0.9.0" -description = "Runtime inspection utilities for typing module." +name = "typing-inspection" +version = "0.4.1" +description = "Runtime typing introspection tools" optional = false -python-versions = "*" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"}, - {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"}, + {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] -mypy-extensions = ">=0.3.0" -typing-extensions = ">=3.7.4" +typing-extensions = ">=4.12.0" [metadata] lock-version = "2.1" -python-versions = ">=3.9" -content-hash = "1f0dcb22a1bf4d933c50fbaab2e7f694592f680adf1171c2dc13507e4259a9c0" +python-versions = ">=3.9.2" +content-hash = "fd5d2a9148a00cbc5258586b48c24f763e191bdc12367f4e92abdbfc15e30679" diff --git a/pylintrc b/pylintrc index f2385e8..e8cd3e8 100644 --- a/pylintrc +++ b/pylintrc @@ -454,7 +454,11 @@ disable=raw-checker-failed, bare-except, broad-exception-caught, fixme, - relative-beyond-top-level + relative-beyond-top-level, + consider-using-with, + wildcard-import, + unused-wildcard-import, + too-many-return-statements # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option @@ -655,4 +659,4 @@ init-import=no # List of qualified module names which can have objects that can redefine # builtins. -redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 3fe1d11..20e84d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,16 +1,14 @@ [project] name = "livepeer-ai" -version = "0.10.0" +version = "0.11.0" description = "Python Client SDK for the Livepeer AI API." authors = [{ name = "Speakeasy" },] readme = "README-PYPI.md" -requires-python = ">=3.9" +requires-python = ">=3.9.2" dependencies = [ - "eval-type-backport >=0.2.0", + "httpcore >=1.0.9", "httpx >=0.28.1", - "pydantic >=2.10.3", - "python-dateutil >=2.8.2", - "typing-inspect >=0.9.0", + "pydantic >=2.11.2", ] [tool.poetry] @@ -27,9 +25,8 @@ include = ["py.typed", "src/livepeer_ai/py.typed"] in-project = true [tool.poetry.group.dev.dependencies] -mypy = "==1.14.1" +mypy = "==1.15.0" pylint = "==3.2.3" -types-python-dateutil = "^2.9.0.20240316" [build-system] requires = ["poetry-core"] @@ -41,6 +38,8 @@ pythonpath = ["src"] [tool.mypy] disable_error_code = "misc" +explicit_package_bases = true +mypy_path = "src" [[tool.mypy.overrides]] module = "typing_inspect" diff --git a/scripts/prepare-readme.py b/scripts/prepare_readme.py similarity index 84% rename from scripts/prepare-readme.py rename to scripts/prepare_readme.py index 8e46a80..cc23cb6 100644 --- a/scripts/prepare-readme.py +++ b/scripts/prepare_readme.py @@ -4,7 +4,7 @@ import shutil try: - with open("README.md", "r") as rh: + with open("README.md", "r", encoding="utf-8") as rh: readme_contents = rh.read() GITHUB_URL = "https://github.com/livepeer/livepeer-ai-python.git" GITHUB_URL = ( @@ -21,13 +21,13 @@ readme_contents, ) - with open("README-PYPI.md", "w") as wh: + with open("README-PYPI.md", "w", encoding="utf-8") as wh: wh.write(readme_contents) except Exception as e: try: print("Failed to rewrite README.md to README-PYPI.md, copying original instead") print(e) shutil.copyfile("README.md", "README-PYPI.md") - except Exception as e: + except Exception as ie: print("Failed to copy README.md to README-PYPI.md") - print(e) + print(ie) diff --git a/scripts/publish.sh b/scripts/publish.sh index ab45b1f..f2f2cf2 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -2,6 +2,6 @@ export POETRY_PYPI_TOKEN_PYPI=${PYPI_TOKEN} -poetry run python scripts/prepare-readme.py +poetry run python scripts/prepare_readme.py poetry publish --build --skip-existing diff --git a/src/livepeer_ai/_hooks/types.py b/src/livepeer_ai/_hooks/types.py index a6bee66..ddc06c7 100644 --- a/src/livepeer_ai/_hooks/types.py +++ b/src/livepeer_ai/_hooks/types.py @@ -3,20 +3,27 @@ from abc import ABC, abstractmethod import httpx from livepeer_ai.httpclient import HttpClient +from livepeer_ai.sdkconfiguration import SDKConfiguration from typing import Any, Callable, List, Optional, Tuple, Union class HookContext: + config: SDKConfiguration + base_url: str operation_id: str oauth2_scopes: Optional[List[str]] = None security_source: Optional[Union[Any, Callable[[], Any]]] = None def __init__( self, + config: SDKConfiguration, + base_url: str, operation_id: str, oauth2_scopes: Optional[List[str]], security_source: Optional[Union[Any, Callable[[], Any]]], ): + self.config = config + self.base_url = base_url self.operation_id = operation_id self.oauth2_scopes = oauth2_scopes self.security_source = security_source @@ -25,21 +32,33 @@ def __init__( class BeforeRequestContext(HookContext): def __init__(self, hook_ctx: HookContext): super().__init__( - hook_ctx.operation_id, hook_ctx.oauth2_scopes, hook_ctx.security_source + hook_ctx.config, + hook_ctx.base_url, + hook_ctx.operation_id, + hook_ctx.oauth2_scopes, + hook_ctx.security_source, ) class AfterSuccessContext(HookContext): def __init__(self, hook_ctx: HookContext): super().__init__( - hook_ctx.operation_id, hook_ctx.oauth2_scopes, hook_ctx.security_source + hook_ctx.config, + hook_ctx.base_url, + hook_ctx.operation_id, + hook_ctx.oauth2_scopes, + hook_ctx.security_source, ) class AfterErrorContext(HookContext): def __init__(self, hook_ctx: HookContext): super().__init__( - hook_ctx.operation_id, hook_ctx.oauth2_scopes, hook_ctx.security_source + hook_ctx.config, + hook_ctx.base_url, + hook_ctx.operation_id, + hook_ctx.oauth2_scopes, + hook_ctx.security_source, ) diff --git a/src/livepeer_ai/_version.py b/src/livepeer_ai/_version.py index 0775e8c..bf09e8b 100644 --- a/src/livepeer_ai/_version.py +++ b/src/livepeer_ai/_version.py @@ -3,10 +3,10 @@ import importlib.metadata __title__: str = "livepeer-ai" -__version__: str = "0.10.0" -__openapi_doc_version__: str = "0.0.0" -__gen_version__: str = "2.499.0" -__user_agent__: str = "speakeasy-sdk/python 0.10.0 2.499.0 0.0.0 livepeer-ai" +__version__: str = "0.11.0" +__openapi_doc_version__: str = "0.13.8" +__gen_version__: str = "2.648.7" +__user_agent__: str = "speakeasy-sdk/python 0.11.0 2.648.7 0.13.8 livepeer-ai" try: if __package__ is not None: diff --git a/src/livepeer_ai/basesdk.py b/src/livepeer_ai/basesdk.py index 91d4a01..3f6fbb1 100644 --- a/src/livepeer_ai/basesdk.py +++ b/src/livepeer_ai/basesdk.py @@ -219,12 +219,12 @@ def do_request( client = self.sdk_configuration.client logger = self.sdk_configuration.debug_logger + hooks = self.sdk_configuration.__dict__["_hooks"] + def do(): http_res = None try: - req = self.sdk_configuration.get_hooks().before_request( - BeforeRequestContext(hook_ctx), request - ) + req = hooks.before_request(BeforeRequestContext(hook_ctx), request) logger.debug( "Request:\nMethod: %s\nURL: %s\nHeaders: %s\nBody: %s", req.method, @@ -232,18 +232,20 @@ def do(): req.headers, get_body_content(req), ) + + if client is None: + raise ValueError("client is required") + http_res = client.send(req, stream=stream) except Exception as e: - _, e = self.sdk_configuration.get_hooks().after_error( - AfterErrorContext(hook_ctx), None, e - ) + _, e = hooks.after_error(AfterErrorContext(hook_ctx), None, e) if e is not None: logger.debug("Request Exception", exc_info=True) raise e if http_res is None: logger.debug("Raising no response SDK error") - raise errors.SDKError("No response received") + raise errors.NoResponseError("No response received") logger.debug( "Response:\nStatus Code: %s\nURL: %s\nHeaders: %s\nBody: %s", @@ -254,7 +256,7 @@ def do(): ) if utils.match_status_codes(error_status_codes, http_res.status_code): - result, err = self.sdk_configuration.get_hooks().after_error( + result, err = hooks.after_error( AfterErrorContext(hook_ctx), http_res, None ) if err is not None: @@ -264,7 +266,7 @@ def do(): http_res = result else: logger.debug("Raising unexpected SDK error") - raise errors.SDKError("Unexpected error occurred") + raise errors.SDKError("Unexpected error occurred", http_res) return http_res @@ -274,9 +276,7 @@ def do(): http_res = do() if not utils.match_status_codes(error_status_codes, http_res.status_code): - http_res = self.sdk_configuration.get_hooks().after_success( - AfterSuccessContext(hook_ctx), http_res - ) + http_res = hooks.after_success(AfterSuccessContext(hook_ctx), http_res) return http_res @@ -291,12 +291,12 @@ async def do_request_async( client = self.sdk_configuration.async_client logger = self.sdk_configuration.debug_logger + hooks = self.sdk_configuration.__dict__["_hooks"] + async def do(): http_res = None try: - req = self.sdk_configuration.get_hooks().before_request( - BeforeRequestContext(hook_ctx), request - ) + req = hooks.before_request(BeforeRequestContext(hook_ctx), request) logger.debug( "Request:\nMethod: %s\nURL: %s\nHeaders: %s\nBody: %s", req.method, @@ -304,18 +304,20 @@ async def do(): req.headers, get_body_content(req), ) + + if client is None: + raise ValueError("client is required") + http_res = await client.send(req, stream=stream) except Exception as e: - _, e = self.sdk_configuration.get_hooks().after_error( - AfterErrorContext(hook_ctx), None, e - ) + _, e = hooks.after_error(AfterErrorContext(hook_ctx), None, e) if e is not None: logger.debug("Request Exception", exc_info=True) raise e if http_res is None: logger.debug("Raising no response SDK error") - raise errors.SDKError("No response received") + raise errors.NoResponseError("No response received") logger.debug( "Response:\nStatus Code: %s\nURL: %s\nHeaders: %s\nBody: %s", @@ -326,7 +328,7 @@ async def do(): ) if utils.match_status_codes(error_status_codes, http_res.status_code): - result, err = self.sdk_configuration.get_hooks().after_error( + result, err = hooks.after_error( AfterErrorContext(hook_ctx), http_res, None ) if err is not None: @@ -336,7 +338,7 @@ async def do(): http_res = result else: logger.debug("Raising unexpected SDK error") - raise errors.SDKError("Unexpected error occurred") + raise errors.SDKError("Unexpected error occurred", http_res) return http_res @@ -348,8 +350,6 @@ async def do(): http_res = await do() if not utils.match_status_codes(error_status_codes, http_res.status_code): - http_res = self.sdk_configuration.get_hooks().after_success( - AfterSuccessContext(hook_ctx), http_res - ) + http_res = hooks.after_success(AfterSuccessContext(hook_ctx), http_res) return http_res diff --git a/src/livepeer_ai/generate.py b/src/livepeer_ai/generate.py index 7fcc2c3..9393f89 100644 --- a/src/livepeer_ai/generate.py +++ b/src/livepeer_ai/generate.py @@ -37,6 +37,8 @@ def text_to_image( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.TextToImageParams) @@ -71,6 +73,8 @@ def text_to_image( http_res = self.do_request( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genTextToImage", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -80,42 +84,37 @@ def text_to_image( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenTextToImageResponse( - image_response=utils.unmarshal_json( - http_res.text, Optional[components.ImageResponse] + image_response=utils.unmarshal_json_response( + Optional[components.ImageResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) async def text_to_image_async( self, @@ -145,6 +144,8 @@ async def text_to_image_async( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.TextToImageParams) @@ -179,6 +180,8 @@ async def text_to_image_async( http_res = await self.do_request_async( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genTextToImage", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -188,42 +191,37 @@ async def text_to_image_async( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenTextToImageResponse( - image_response=utils.unmarshal_json( - http_res.text, Optional[components.ImageResponse] + image_response=utils.unmarshal_json_response( + Optional[components.ImageResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) def image_to_image( self, @@ -253,6 +251,8 @@ def image_to_image( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.BodyGenImageToImage) @@ -287,6 +287,8 @@ def image_to_image( http_res = self.do_request( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genImageToImage", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -296,42 +298,37 @@ def image_to_image( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenImageToImageResponse( - image_response=utils.unmarshal_json( - http_res.text, Optional[components.ImageResponse] + image_response=utils.unmarshal_json_response( + Optional[components.ImageResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) async def image_to_image_async( self, @@ -361,6 +358,8 @@ async def image_to_image_async( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.BodyGenImageToImage) @@ -395,6 +394,8 @@ async def image_to_image_async( http_res = await self.do_request_async( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genImageToImage", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -404,42 +405,37 @@ async def image_to_image_async( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenImageToImageResponse( - image_response=utils.unmarshal_json( - http_res.text, Optional[components.ImageResponse] + image_response=utils.unmarshal_json_response( + Optional[components.ImageResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) def image_to_video( self, @@ -469,6 +465,8 @@ def image_to_video( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.BodyGenImageToVideo) @@ -503,6 +501,8 @@ def image_to_video( http_res = self.do_request( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genImageToVideo", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -512,42 +512,37 @@ def image_to_video( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenImageToVideoResponse( - video_response=utils.unmarshal_json( - http_res.text, Optional[components.VideoResponse] + video_response=utils.unmarshal_json_response( + Optional[components.VideoResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) async def image_to_video_async( self, @@ -577,6 +572,8 @@ async def image_to_video_async( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.BodyGenImageToVideo) @@ -611,6 +608,8 @@ async def image_to_video_async( http_res = await self.do_request_async( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genImageToVideo", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -620,42 +619,37 @@ async def image_to_video_async( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenImageToVideoResponse( - video_response=utils.unmarshal_json( - http_res.text, Optional[components.VideoResponse] + video_response=utils.unmarshal_json_response( + Optional[components.VideoResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) def upscale( self, @@ -683,6 +677,8 @@ def upscale( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.BodyGenUpscale) @@ -717,6 +713,8 @@ def upscale( http_res = self.do_request( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genUpscale", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -726,42 +724,37 @@ def upscale( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenUpscaleResponse( - image_response=utils.unmarshal_json( - http_res.text, Optional[components.ImageResponse] + image_response=utils.unmarshal_json_response( + Optional[components.ImageResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) async def upscale_async( self, @@ -789,6 +782,8 @@ async def upscale_async( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.BodyGenUpscale) @@ -823,6 +818,8 @@ async def upscale_async( http_res = await self.do_request_async( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genUpscale", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -832,42 +829,37 @@ async def upscale_async( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenUpscaleResponse( - image_response=utils.unmarshal_json( - http_res.text, Optional[components.ImageResponse] + image_response=utils.unmarshal_json_response( + Optional[components.ImageResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) def audio_to_text( self, @@ -897,6 +889,8 @@ def audio_to_text( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.BodyGenAudioToText) @@ -931,6 +925,8 @@ def audio_to_text( http_res = self.do_request( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genAudioToText", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -940,44 +936,39 @@ def audio_to_text( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenAudioToTextResponse( - text_response=utils.unmarshal_json( - http_res.text, Optional[components.TextResponse] + text_response=utils.unmarshal_json_response( + Optional[components.TextResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response( http_res, ["400", "401", "413", "415"], "application/json" ): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) async def audio_to_text_async( self, @@ -1007,6 +998,8 @@ async def audio_to_text_async( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.BodyGenAudioToText) @@ -1041,6 +1034,8 @@ async def audio_to_text_async( http_res = await self.do_request_async( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genAudioToText", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -1050,44 +1045,39 @@ async def audio_to_text_async( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenAudioToTextResponse( - text_response=utils.unmarshal_json( - http_res.text, Optional[components.TextResponse] + text_response=utils.unmarshal_json_response( + Optional[components.TextResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response( http_res, ["400", "401", "413", "415"], "application/json" ): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) def segment_anything2( self, @@ -1118,6 +1108,8 @@ def segment_anything2( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.BodyGenSegmentAnything2) @@ -1152,6 +1144,8 @@ def segment_anything2( http_res = self.do_request( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genSegmentAnything2", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -1161,42 +1155,37 @@ def segment_anything2( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenSegmentAnything2Response( - masks_response=utils.unmarshal_json( - http_res.text, Optional[components.MasksResponse] + masks_response=utils.unmarshal_json_response( + Optional[components.MasksResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) async def segment_anything2_async( self, @@ -1227,6 +1216,8 @@ async def segment_anything2_async( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.BodyGenSegmentAnything2) @@ -1261,6 +1252,8 @@ async def segment_anything2_async( http_res = await self.do_request_async( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genSegmentAnything2", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -1270,42 +1263,37 @@ async def segment_anything2_async( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenSegmentAnything2Response( - masks_response=utils.unmarshal_json( - http_res.text, Optional[components.MasksResponse] + masks_response=utils.unmarshal_json_response( + Optional[components.MasksResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) def llm( self, @@ -1333,6 +1321,8 @@ def llm( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.LLMRequest) @@ -1367,6 +1357,8 @@ def llm( http_res = self.do_request( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genLLM", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -1376,42 +1368,37 @@ def llm( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenLLMResponse( - llm_response=utils.unmarshal_json( - http_res.text, Optional[components.LLMResponse] + llm_response=utils.unmarshal_json_response( + Optional[components.LLMResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) async def llm_async( self, @@ -1439,6 +1426,8 @@ async def llm_async( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.LLMRequest) @@ -1473,6 +1462,8 @@ async def llm_async( http_res = await self.do_request_async( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genLLM", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -1482,42 +1473,37 @@ async def llm_async( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenLLMResponse( - llm_response=utils.unmarshal_json( - http_res.text, Optional[components.LLMResponse] + llm_response=utils.unmarshal_json_response( + Optional[components.LLMResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) def image_to_text( self, @@ -1547,6 +1533,8 @@ def image_to_text( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.BodyGenImageToText) @@ -1581,6 +1569,8 @@ def image_to_text( http_res = self.do_request( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genImageToText", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -1590,42 +1580,37 @@ def image_to_text( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenImageToTextResponse( - image_to_text_response=utils.unmarshal_json( - http_res.text, Optional[components.ImageToTextResponse] + image_to_text_response=utils.unmarshal_json_response( + Optional[components.ImageToTextResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401", "413"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) async def image_to_text_async( self, @@ -1655,6 +1640,8 @@ async def image_to_text_async( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.BodyGenImageToText) @@ -1689,6 +1676,8 @@ async def image_to_text_async( http_res = await self.do_request_async( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genImageToText", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -1698,42 +1687,37 @@ async def image_to_text_async( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenImageToTextResponse( - image_to_text_response=utils.unmarshal_json( - http_res.text, Optional[components.ImageToTextResponse] + image_to_text_response=utils.unmarshal_json_response( + Optional[components.ImageToTextResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401", "413"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) def live_video_to_video( self, @@ -1764,6 +1748,8 @@ def live_video_to_video( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.LiveVideoToVideoParams) @@ -1798,6 +1784,8 @@ def live_video_to_video( http_res = self.do_request( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genLiveVideoToVideo", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -1807,42 +1795,37 @@ def live_video_to_video( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenLiveVideoToVideoResponse( - live_video_to_video_response=utils.unmarshal_json( - http_res.text, Optional[components.LiveVideoToVideoResponse] + live_video_to_video_response=utils.unmarshal_json_response( + Optional[components.LiveVideoToVideoResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) async def live_video_to_video_async( self, @@ -1873,6 +1856,8 @@ async def live_video_to_video_async( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.LiveVideoToVideoParams) @@ -1907,6 +1892,8 @@ async def live_video_to_video_async( http_res = await self.do_request_async( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genLiveVideoToVideo", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -1916,42 +1903,37 @@ async def live_video_to_video_async( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenLiveVideoToVideoResponse( - live_video_to_video_response=utils.unmarshal_json( - http_res.text, Optional[components.LiveVideoToVideoResponse] + live_video_to_video_response=utils.unmarshal_json_response( + Optional[components.LiveVideoToVideoResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) def text_to_speech( self, @@ -1981,6 +1963,8 @@ def text_to_speech( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.TextToSpeechParams) @@ -2015,6 +1999,8 @@ def text_to_speech( http_res = self.do_request( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genTextToSpeech", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -2024,42 +2010,37 @@ def text_to_speech( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenTextToSpeechResponse( - audio_response=utils.unmarshal_json( - http_res.text, Optional[components.AudioResponse] + audio_response=utils.unmarshal_json_response( + Optional[components.AudioResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = utils.stream_to_text(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) async def text_to_speech_async( self, @@ -2089,6 +2070,8 @@ async def text_to_speech_async( if server_url is not None: base_url = server_url + else: + base_url = self._get_url(base_url, url_variables) if not isinstance(request, BaseModel): request = utils.unmarshal(request, components.TextToSpeechParams) @@ -2123,6 +2106,8 @@ async def text_to_speech_async( http_res = await self.do_request_async( hook_ctx=HookContext( + config=self.sdk_configuration, + base_url=base_url or "", operation_id="genTextToSpeech", oauth2_scopes=[], security_source=self.sdk_configuration.security, @@ -2132,39 +2117,34 @@ async def text_to_speech_async( retry_config=retry_config, ) - data: Any = None + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): return operations.GenTextToSpeechResponse( - audio_response=utils.unmarshal_json( - http_res.text, Optional[components.AudioResponse] + audio_response=utils.unmarshal_json_response( + Optional[components.AudioResponse], http_res ), http_meta=components.HTTPMetadata(request=req, response=http_res), ) if utils.match_response(http_res, ["400", "401"], "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "422", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPValidationErrorData) - raise errors.HTTPValidationError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPValidationErrorData, http_res + ) + raise errors.HTTPValidationError(response_data, http_res) if utils.match_response(http_res, "500", "application/json"): - data = utils.unmarshal_json(http_res.text, errors.HTTPErrorData) - raise errors.HTTPError(data=data) + response_data = utils.unmarshal_json_response( + errors.HTTPErrorData, http_res + ) + raise errors.HTTPError(response_data, http_res) if utils.match_response(http_res, "4XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) if utils.match_response(http_res, "5XX", "*"): http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - "API error occurred", http_res.status_code, http_res_text, http_res - ) + raise errors.SDKError("API error occurred", http_res, http_res_text) - content_type = http_res.headers.get("Content-Type") - http_res_text = await utils.stream_to_text_async(http_res) - raise errors.SDKError( - f"Unexpected response received (code: {http_res.status_code}, type: {content_type})", - http_res.status_code, - http_res_text, - http_res, - ) + raise errors.SDKError("Unexpected response received", http_res) diff --git a/src/livepeer_ai/httpclient.py b/src/livepeer_ai/httpclient.py index 9dc43cb..47b052c 100644 --- a/src/livepeer_ai/httpclient.py +++ b/src/livepeer_ai/httpclient.py @@ -2,7 +2,6 @@ # pyright: reportReturnType = false import asyncio -from concurrent.futures import ThreadPoolExecutor from typing_extensions import Protocol, runtime_checkable import httpx from typing import Any, Optional, Union @@ -94,7 +93,9 @@ class ClientOwner(Protocol): def close_clients( owner: ClientOwner, sync_client: Union[HttpClient, None], + sync_client_supplied: bool, async_client: Union[AsyncHttpClient, None], + async_client_supplied: bool, ) -> None: """ A finalizer function that is meant to be used with weakref.finalize to close @@ -107,28 +108,19 @@ def close_clients( owner.client = None owner.async_client = None - if sync_client is not None: + if sync_client is not None and not sync_client_supplied: try: sync_client.close() except Exception: pass - if async_client is not None: - is_async = False + if async_client is not None and not async_client_supplied: try: - asyncio.get_running_loop() - is_async = True + loop = asyncio.get_running_loop() + asyncio.run_coroutine_threadsafe(async_client.aclose(), loop) except RuntimeError: - pass - - try: - # If this function is called in an async loop then start another - # loop in a separate thread to close the async http client. - if is_async: - with ThreadPoolExecutor(max_workers=1) as executor: - future = executor.submit(asyncio.run, async_client.aclose()) - future.result() - else: + try: asyncio.run(async_client.aclose()) - except Exception: - pass + except RuntimeError: + # best effort + pass diff --git a/src/livepeer_ai/models/__init__.py b/src/livepeer_ai/models/__init__.py new file mode 100644 index 0000000..726fc5e --- /dev/null +++ b/src/livepeer_ai/models/__init__.py @@ -0,0 +1,3 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +# package diff --git a/src/livepeer_ai/models/components/__init__.py b/src/livepeer_ai/models/components/__init__.py index 469c48b..fc296aa 100644 --- a/src/livepeer_ai/models/components/__init__.py +++ b/src/livepeer_ai/models/components/__init__.py @@ -1,77 +1,80 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" -from .apierror import APIError, APIErrorTypedDict -from .audioresponse import AudioResponse, AudioResponseTypedDict -from .body_genaudiototext import ( - Audio, - AudioTypedDict, - BodyGenAudioToText, - BodyGenAudioToTextTypedDict, -) -from .body_genimagetoimage import ( - BodyGenImageToImage, - BodyGenImageToImageTypedDict, - Image, - ImageTypedDict, -) -from .body_genimagetotext import ( - BodyGenImageToText, - BodyGenImageToTextImage, - BodyGenImageToTextImageTypedDict, - BodyGenImageToTextTypedDict, -) -from .body_genimagetovideo import ( - BodyGenImageToVideo, - BodyGenImageToVideoImage, - BodyGenImageToVideoImageTypedDict, - BodyGenImageToVideoTypedDict, -) -from .body_gensegmentanything2 import ( - BodyGenSegmentAnything2, - BodyGenSegmentAnything2Image, - BodyGenSegmentAnything2ImageTypedDict, - BodyGenSegmentAnything2TypedDict, -) -from .body_genupscale import ( - BodyGenUpscale, - BodyGenUpscaleImage, - BodyGenUpscaleImageTypedDict, - BodyGenUpscaleTypedDict, -) -from .chunk import Chunk, ChunkTypedDict -from .httpmetadata import HTTPMetadata, HTTPMetadataTypedDict -from .imageresponse import ImageResponse, ImageResponseTypedDict -from .imagetotextresponse import ImageToTextResponse, ImageToTextResponseTypedDict -from .livevideotovideoparams import ( - LiveVideoToVideoParams, - LiveVideoToVideoParamsTypedDict, - Params, - ParamsTypedDict, -) -from .livevideotovideoresponse import ( - LiveVideoToVideoResponse, - LiveVideoToVideoResponseTypedDict, -) -from .llmchoice import LLMChoice, LLMChoiceTypedDict -from .llmmessage import LLMMessage, LLMMessageTypedDict -from .llmrequest import LLMRequest, LLMRequestTypedDict -from .llmresponse import LLMResponse, LLMResponseTypedDict -from .llmtokenusage import LLMTokenUsage, LLMTokenUsageTypedDict -from .masksresponse import MasksResponse, MasksResponseTypedDict -from .media import Media, MediaTypedDict -from .mediaurl import MediaURL, MediaURLTypedDict -from .security import Security, SecurityTypedDict -from .textresponse import TextResponse, TextResponseTypedDict -from .texttoimageparams import TextToImageParams, TextToImageParamsTypedDict -from .texttospeechparams import TextToSpeechParams, TextToSpeechParamsTypedDict -from .validationerror import ( - Loc, - LocTypedDict, - ValidationError, - ValidationErrorTypedDict, -) -from .videoresponse import VideoResponse, VideoResponseTypedDict +from typing import TYPE_CHECKING +from importlib import import_module +if TYPE_CHECKING: + from .apierror import APIError, APIErrorTypedDict + from .audioresponse import AudioResponse, AudioResponseTypedDict + from .body_genaudiototext import ( + Audio, + AudioTypedDict, + BodyGenAudioToText, + BodyGenAudioToTextTypedDict, + ) + from .body_genimagetoimage import ( + BodyGenImageToImage, + BodyGenImageToImageTypedDict, + Image, + ImageTypedDict, + ) + from .body_genimagetotext import ( + BodyGenImageToText, + BodyGenImageToTextImage, + BodyGenImageToTextImageTypedDict, + BodyGenImageToTextTypedDict, + ) + from .body_genimagetovideo import ( + BodyGenImageToVideo, + BodyGenImageToVideoImage, + BodyGenImageToVideoImageTypedDict, + BodyGenImageToVideoTypedDict, + ) + from .body_gensegmentanything2 import ( + BodyGenSegmentAnything2, + BodyGenSegmentAnything2Image, + BodyGenSegmentAnything2ImageTypedDict, + BodyGenSegmentAnything2TypedDict, + ) + from .body_genupscale import ( + BodyGenUpscale, + BodyGenUpscaleImage, + BodyGenUpscaleImageTypedDict, + BodyGenUpscaleTypedDict, + ) + from .chunk import Chunk, ChunkTypedDict + from .httpmetadata import HTTPMetadata, HTTPMetadataTypedDict + from .imageresponse import ImageResponse, ImageResponseTypedDict + from .imagetotextresponse import ImageToTextResponse, ImageToTextResponseTypedDict + from .livevideotovideoparams import ( + LiveVideoToVideoParams, + LiveVideoToVideoParamsTypedDict, + Params, + ParamsTypedDict, + ) + from .livevideotovideoresponse import ( + LiveVideoToVideoResponse, + LiveVideoToVideoResponseTypedDict, + ) + from .llmchoice import LLMChoice, LLMChoiceTypedDict + from .llmmessage import LLMMessage, LLMMessageTypedDict + from .llmrequest import LLMRequest, LLMRequestTypedDict + from .llmresponse import LLMResponse, LLMResponseTypedDict + from .llmtokenusage import LLMTokenUsage, LLMTokenUsageTypedDict + from .masksresponse import MasksResponse, MasksResponseTypedDict + from .media import Media, MediaTypedDict + from .mediaurl import MediaURL, MediaURLTypedDict + from .security import Security, SecurityTypedDict + from .textresponse import TextResponse, TextResponseTypedDict + from .texttoimageparams import TextToImageParams, TextToImageParamsTypedDict + from .texttospeechparams import TextToSpeechParams, TextToSpeechParamsTypedDict + from .validationerror import ( + Loc, + LocTypedDict, + ValidationError, + ValidationErrorTypedDict, + ) + from .videoresponse import VideoResponse, VideoResponseTypedDict __all__ = [ "APIError", @@ -147,3 +150,104 @@ "VideoResponse", "VideoResponseTypedDict", ] + +_dynamic_imports: dict[str, str] = { + "APIError": ".apierror", + "APIErrorTypedDict": ".apierror", + "AudioResponse": ".audioresponse", + "AudioResponseTypedDict": ".audioresponse", + "Audio": ".body_genaudiototext", + "AudioTypedDict": ".body_genaudiototext", + "BodyGenAudioToText": ".body_genaudiototext", + "BodyGenAudioToTextTypedDict": ".body_genaudiototext", + "BodyGenImageToImage": ".body_genimagetoimage", + "BodyGenImageToImageTypedDict": ".body_genimagetoimage", + "Image": ".body_genimagetoimage", + "ImageTypedDict": ".body_genimagetoimage", + "BodyGenImageToText": ".body_genimagetotext", + "BodyGenImageToTextImage": ".body_genimagetotext", + "BodyGenImageToTextImageTypedDict": ".body_genimagetotext", + "BodyGenImageToTextTypedDict": ".body_genimagetotext", + "BodyGenImageToVideo": ".body_genimagetovideo", + "BodyGenImageToVideoImage": ".body_genimagetovideo", + "BodyGenImageToVideoImageTypedDict": ".body_genimagetovideo", + "BodyGenImageToVideoTypedDict": ".body_genimagetovideo", + "BodyGenSegmentAnything2": ".body_gensegmentanything2", + "BodyGenSegmentAnything2Image": ".body_gensegmentanything2", + "BodyGenSegmentAnything2ImageTypedDict": ".body_gensegmentanything2", + "BodyGenSegmentAnything2TypedDict": ".body_gensegmentanything2", + "BodyGenUpscale": ".body_genupscale", + "BodyGenUpscaleImage": ".body_genupscale", + "BodyGenUpscaleImageTypedDict": ".body_genupscale", + "BodyGenUpscaleTypedDict": ".body_genupscale", + "Chunk": ".chunk", + "ChunkTypedDict": ".chunk", + "HTTPMetadata": ".httpmetadata", + "HTTPMetadataTypedDict": ".httpmetadata", + "ImageResponse": ".imageresponse", + "ImageResponseTypedDict": ".imageresponse", + "ImageToTextResponse": ".imagetotextresponse", + "ImageToTextResponseTypedDict": ".imagetotextresponse", + "LiveVideoToVideoParams": ".livevideotovideoparams", + "LiveVideoToVideoParamsTypedDict": ".livevideotovideoparams", + "Params": ".livevideotovideoparams", + "ParamsTypedDict": ".livevideotovideoparams", + "LiveVideoToVideoResponse": ".livevideotovideoresponse", + "LiveVideoToVideoResponseTypedDict": ".livevideotovideoresponse", + "LLMChoice": ".llmchoice", + "LLMChoiceTypedDict": ".llmchoice", + "LLMMessage": ".llmmessage", + "LLMMessageTypedDict": ".llmmessage", + "LLMRequest": ".llmrequest", + "LLMRequestTypedDict": ".llmrequest", + "LLMResponse": ".llmresponse", + "LLMResponseTypedDict": ".llmresponse", + "LLMTokenUsage": ".llmtokenusage", + "LLMTokenUsageTypedDict": ".llmtokenusage", + "MasksResponse": ".masksresponse", + "MasksResponseTypedDict": ".masksresponse", + "Media": ".media", + "MediaTypedDict": ".media", + "MediaURL": ".mediaurl", + "MediaURLTypedDict": ".mediaurl", + "Security": ".security", + "SecurityTypedDict": ".security", + "TextResponse": ".textresponse", + "TextResponseTypedDict": ".textresponse", + "TextToImageParams": ".texttoimageparams", + "TextToImageParamsTypedDict": ".texttoimageparams", + "TextToSpeechParams": ".texttospeechparams", + "TextToSpeechParamsTypedDict": ".texttospeechparams", + "Loc": ".validationerror", + "LocTypedDict": ".validationerror", + "ValidationError": ".validationerror", + "ValidationErrorTypedDict": ".validationerror", + "VideoResponse": ".videoresponse", + "VideoResponseTypedDict": ".videoresponse", +} + + +def __getattr__(attr_name: str) -> object: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__} " + ) + + try: + module = import_module(module_name, __package__) + result = getattr(module, attr_name) + return result + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) diff --git a/src/livepeer_ai/models/components/livevideotovideoparams.py b/src/livepeer_ai/models/components/livevideotovideoparams.py index 3afd049..de26c6c 100644 --- a/src/livepeer_ai/models/components/livevideotovideoparams.py +++ b/src/livepeer_ai/models/components/livevideotovideoparams.py @@ -27,6 +27,12 @@ class LiveVideoToVideoParamsTypedDict(TypedDict): r"""Name of the pipeline to run in the live video to video job. Notice that this is named model_id for consistency with other routes, but it does not refer to a Hugging Face model ID. The exact model(s) depends on the pipeline implementation and might be configurable via the `params` argument.""" params: NotRequired[ParamsTypedDict] r"""Initial parameters for the pipeline.""" + gateway_request_id: NotRequired[str] + r"""The ID of the Gateway request (for logging purposes).""" + manifest_id: NotRequired[str] + r"""The manifest ID from the orchestrator (for logging purposes).""" + stream_id: NotRequired[str] + r"""The Stream ID (for logging purposes).""" class LiveVideoToVideoParams(BaseModel): @@ -47,3 +53,12 @@ class LiveVideoToVideoParams(BaseModel): params: Optional[Params] = None r"""Initial parameters for the pipeline.""" + + gateway_request_id: Optional[str] = "" + r"""The ID of the Gateway request (for logging purposes).""" + + manifest_id: Optional[str] = "" + r"""The manifest ID from the orchestrator (for logging purposes).""" + + stream_id: Optional[str] = "" + r"""The Stream ID (for logging purposes).""" diff --git a/src/livepeer_ai/models/components/livevideotovideoresponse.py b/src/livepeer_ai/models/components/livevideotovideoresponse.py index cba67ee..c23d05e 100644 --- a/src/livepeer_ai/models/components/livevideotovideoresponse.py +++ b/src/livepeer_ai/models/components/livevideotovideoresponse.py @@ -17,6 +17,10 @@ class LiveVideoToVideoResponseTypedDict(TypedDict): r"""URL for updating the live video-to-video generation""" events_url: NotRequired[str] r"""URL for subscribing to events for pipeline status and logs""" + request_id: NotRequired[str] + r"""The ID generated for this request""" + manifest_id: NotRequired[str] + r"""Orchestrator manifest ID for this request""" class LiveVideoToVideoResponse(BaseModel): @@ -33,3 +37,9 @@ class LiveVideoToVideoResponse(BaseModel): events_url: Optional[str] = "" r"""URL for subscribing to events for pipeline status and logs""" + + request_id: Optional[str] = "" + r"""The ID generated for this request""" + + manifest_id: Optional[str] = "" + r"""Orchestrator manifest ID for this request""" diff --git a/src/livepeer_ai/models/errors/__init__.py b/src/livepeer_ai/models/errors/__init__.py index d495052..4dd85cf 100644 --- a/src/livepeer_ai/models/errors/__init__.py +++ b/src/livepeer_ai/models/errors/__init__.py @@ -1,14 +1,60 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" -from .httperror import HTTPError, HTTPErrorData -from .httpvalidationerror import HTTPValidationError, HTTPValidationErrorData -from .sdkerror import SDKError +from typing import TYPE_CHECKING +from importlib import import_module +if TYPE_CHECKING: + from .httperror import HTTPError, HTTPErrorData + from .httpvalidationerror import HTTPValidationError, HTTPValidationErrorData + from .livepeererror import LivepeerError + from .no_response_error import NoResponseError + from .responsevalidationerror import ResponseValidationError + from .sdkerror import SDKError __all__ = [ "HTTPError", "HTTPErrorData", "HTTPValidationError", "HTTPValidationErrorData", + "LivepeerError", + "NoResponseError", + "ResponseValidationError", "SDKError", ] + +_dynamic_imports: dict[str, str] = { + "HTTPError": ".httperror", + "HTTPErrorData": ".httperror", + "HTTPValidationError": ".httpvalidationerror", + "HTTPValidationErrorData": ".httpvalidationerror", + "LivepeerError": ".livepeererror", + "NoResponseError": ".no_response_error", + "ResponseValidationError": ".responsevalidationerror", + "SDKError": ".sdkerror", +} + + +def __getattr__(attr_name: str) -> object: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__} " + ) + + try: + module = import_module(module_name, __package__) + result = getattr(module, attr_name) + return result + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) diff --git a/src/livepeer_ai/models/errors/httperror.py b/src/livepeer_ai/models/errors/httperror.py index 78bcc59..e982d3f 100644 --- a/src/livepeer_ai/models/errors/httperror.py +++ b/src/livepeer_ai/models/errors/httperror.py @@ -1,9 +1,11 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" from __future__ import annotations -from livepeer_ai import utils +import httpx from livepeer_ai.models.components import apierror as components_apierror +from livepeer_ai.models.errors import LivepeerError from livepeer_ai.types import BaseModel +from typing import Optional class HTTPErrorData(BaseModel): @@ -11,13 +13,17 @@ class HTTPErrorData(BaseModel): r"""Detailed error information.""" -class HTTPError(Exception): +class HTTPError(LivepeerError): r"""HTTP error response model.""" data: HTTPErrorData - def __init__(self, data: HTTPErrorData): + def __init__( + self, + data: HTTPErrorData, + raw_response: httpx.Response, + body: Optional[str] = None, + ): + message = body or raw_response.text + super().__init__(message, raw_response, body) self.data = data - - def __str__(self) -> str: - return utils.marshal_json(self.data, HTTPErrorData) diff --git a/src/livepeer_ai/models/errors/httpvalidationerror.py b/src/livepeer_ai/models/errors/httpvalidationerror.py index f3217e1..2b6dc73 100644 --- a/src/livepeer_ai/models/errors/httpvalidationerror.py +++ b/src/livepeer_ai/models/errors/httpvalidationerror.py @@ -1,8 +1,9 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" from __future__ import annotations -from livepeer_ai import utils +import httpx from livepeer_ai.models.components import validationerror as components_validationerror +from livepeer_ai.models.errors import LivepeerError from livepeer_ai.types import BaseModel from typing import List, Optional @@ -11,11 +12,15 @@ class HTTPValidationErrorData(BaseModel): detail: Optional[List[components_validationerror.ValidationError]] = None -class HTTPValidationError(Exception): +class HTTPValidationError(LivepeerError): data: HTTPValidationErrorData - def __init__(self, data: HTTPValidationErrorData): + def __init__( + self, + data: HTTPValidationErrorData, + raw_response: httpx.Response, + body: Optional[str] = None, + ): + message = body or raw_response.text + super().__init__(message, raw_response, body) self.data = data - - def __str__(self) -> str: - return utils.marshal_json(self.data, HTTPValidationErrorData) diff --git a/src/livepeer_ai/models/errors/livepeererror.py b/src/livepeer_ai/models/errors/livepeererror.py new file mode 100644 index 0000000..aa59f9c --- /dev/null +++ b/src/livepeer_ai/models/errors/livepeererror.py @@ -0,0 +1,26 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +import httpx +from typing import Optional + + +class LivepeerError(Exception): + """The base class for all HTTP error responses.""" + + message: str + status_code: int + body: str + headers: httpx.Headers + raw_response: httpx.Response + + def __init__( + self, message: str, raw_response: httpx.Response, body: Optional[str] = None + ): + self.message = message + self.status_code = raw_response.status_code + self.body = body if body is not None else raw_response.text + self.headers = raw_response.headers + self.raw_response = raw_response + + def __str__(self): + return self.message diff --git a/src/livepeer_ai/models/errors/no_response_error.py b/src/livepeer_ai/models/errors/no_response_error.py new file mode 100644 index 0000000..f98beea --- /dev/null +++ b/src/livepeer_ai/models/errors/no_response_error.py @@ -0,0 +1,13 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +class NoResponseError(Exception): + """Error raised when no HTTP response is received from the server.""" + + message: str + + def __init__(self, message: str = "No response received"): + self.message = message + super().__init__(message) + + def __str__(self): + return self.message diff --git a/src/livepeer_ai/models/errors/responsevalidationerror.py b/src/livepeer_ai/models/errors/responsevalidationerror.py new file mode 100644 index 0000000..8096769 --- /dev/null +++ b/src/livepeer_ai/models/errors/responsevalidationerror.py @@ -0,0 +1,25 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +import httpx +from typing import Optional + +from livepeer_ai.models.errors import LivepeerError + + +class ResponseValidationError(LivepeerError): + """Error raised when there is a type mismatch between the response data and the expected Pydantic model.""" + + def __init__( + self, + message: str, + raw_response: httpx.Response, + cause: Exception, + body: Optional[str] = None, + ): + message = f"{message}: {cause}" + super().__init__(message, raw_response, body) + + @property + def cause(self): + """Normally the Pydantic ValidationError""" + return self.__cause__ diff --git a/src/livepeer_ai/models/errors/sdkerror.py b/src/livepeer_ai/models/errors/sdkerror.py index 03216cb..2bdf59c 100644 --- a/src/livepeer_ai/models/errors/sdkerror.py +++ b/src/livepeer_ai/models/errors/sdkerror.py @@ -1,22 +1,38 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" -from dataclasses import dataclass -from typing import Optional import httpx +from typing import Optional + +from livepeer_ai.models.errors import LivepeerError + +MAX_MESSAGE_LEN = 10_000 + + +class SDKError(LivepeerError): + """The fallback error class if no more specific error class is matched.""" + + def __init__( + self, message: str, raw_response: httpx.Response, body: Optional[str] = None + ): + body_display = body or raw_response.text or '""' + if message: + message += ": " + message += f"Status {raw_response.status_code}" -@dataclass -class SDKError(Exception): - """Represents an error returned by the API.""" + headers = raw_response.headers + content_type = headers.get("content-type", '""') + if content_type != "application/json": + if " " in content_type: + content_type = f'"{content_type}"' + message += f" Content-Type {content_type}" - message: str - status_code: int = -1 - body: str = "" - raw_response: Optional[httpx.Response] = None + if len(body_display) > MAX_MESSAGE_LEN: + truncated = body_display[:MAX_MESSAGE_LEN] + remaining = len(body_display) - MAX_MESSAGE_LEN + body_display = f"{truncated}...and {remaining} more chars" - def __str__(self): - body = "" - if len(self.body) > 0: - body = f"\n{self.body}" + message += f". Body: {body_display}" + message = message.strip() - return f"{self.message}: Status {self.status_code}{body}" + super().__init__(message, raw_response, body) diff --git a/src/livepeer_ai/models/operations/__init__.py b/src/livepeer_ai/models/operations/__init__.py index 438ec50..3461bff 100644 --- a/src/livepeer_ai/models/operations/__init__.py +++ b/src/livepeer_ai/models/operations/__init__.py @@ -1,22 +1,34 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" -from .genaudiototext import GenAudioToTextResponse, GenAudioToTextResponseTypedDict -from .genimagetoimage import GenImageToImageResponse, GenImageToImageResponseTypedDict -from .genimagetotext import GenImageToTextResponse, GenImageToTextResponseTypedDict -from .genimagetovideo import GenImageToVideoResponse, GenImageToVideoResponseTypedDict -from .genlivevideotovideo import ( - GenLiveVideoToVideoResponse, - GenLiveVideoToVideoResponseTypedDict, -) -from .genllm import GenLLMResponse, GenLLMResponseTypedDict -from .gensegmentanything2 import ( - GenSegmentAnything2Response, - GenSegmentAnything2ResponseTypedDict, -) -from .gentexttoimage import GenTextToImageResponse, GenTextToImageResponseTypedDict -from .gentexttospeech import GenTextToSpeechResponse, GenTextToSpeechResponseTypedDict -from .genupscale import GenUpscaleResponse, GenUpscaleResponseTypedDict +from typing import TYPE_CHECKING +from importlib import import_module +if TYPE_CHECKING: + from .genaudiototext import GenAudioToTextResponse, GenAudioToTextResponseTypedDict + from .genimagetoimage import ( + GenImageToImageResponse, + GenImageToImageResponseTypedDict, + ) + from .genimagetotext import GenImageToTextResponse, GenImageToTextResponseTypedDict + from .genimagetovideo import ( + GenImageToVideoResponse, + GenImageToVideoResponseTypedDict, + ) + from .genlivevideotovideo import ( + GenLiveVideoToVideoResponse, + GenLiveVideoToVideoResponseTypedDict, + ) + from .genllm import GenLLMResponse, GenLLMResponseTypedDict + from .gensegmentanything2 import ( + GenSegmentAnything2Response, + GenSegmentAnything2ResponseTypedDict, + ) + from .gentexttoimage import GenTextToImageResponse, GenTextToImageResponseTypedDict + from .gentexttospeech import ( + GenTextToSpeechResponse, + GenTextToSpeechResponseTypedDict, + ) + from .genupscale import GenUpscaleResponse, GenUpscaleResponseTypedDict __all__ = [ "GenAudioToTextResponse", @@ -40,3 +52,52 @@ "GenUpscaleResponse", "GenUpscaleResponseTypedDict", ] + +_dynamic_imports: dict[str, str] = { + "GenAudioToTextResponse": ".genaudiototext", + "GenAudioToTextResponseTypedDict": ".genaudiototext", + "GenImageToImageResponse": ".genimagetoimage", + "GenImageToImageResponseTypedDict": ".genimagetoimage", + "GenImageToTextResponse": ".genimagetotext", + "GenImageToTextResponseTypedDict": ".genimagetotext", + "GenImageToVideoResponse": ".genimagetovideo", + "GenImageToVideoResponseTypedDict": ".genimagetovideo", + "GenLiveVideoToVideoResponse": ".genlivevideotovideo", + "GenLiveVideoToVideoResponseTypedDict": ".genlivevideotovideo", + "GenLLMResponse": ".genllm", + "GenLLMResponseTypedDict": ".genllm", + "GenSegmentAnything2Response": ".gensegmentanything2", + "GenSegmentAnything2ResponseTypedDict": ".gensegmentanything2", + "GenTextToImageResponse": ".gentexttoimage", + "GenTextToImageResponseTypedDict": ".gentexttoimage", + "GenTextToSpeechResponse": ".gentexttospeech", + "GenTextToSpeechResponseTypedDict": ".gentexttospeech", + "GenUpscaleResponse": ".genupscale", + "GenUpscaleResponseTypedDict": ".genupscale", +} + + +def __getattr__(attr_name: str) -> object: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"No {attr_name} found in _dynamic_imports for module name -> {__name__} " + ) + + try: + module = import_module(module_name, __package__) + result = getattr(module, attr_name) + return result + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) diff --git a/src/livepeer_ai/sdk.py b/src/livepeer_ai/sdk.py index 59d8ab5..93265d8 100644 --- a/src/livepeer_ai/sdk.py +++ b/src/livepeer_ai/sdk.py @@ -6,19 +6,25 @@ from .utils.logger import Logger, get_default_logger from .utils.retries import RetryConfig import httpx +import importlib from livepeer_ai import utils from livepeer_ai._hooks import SDKHooks -from livepeer_ai.generate import Generate from livepeer_ai.models import components from livepeer_ai.types import OptionalNullable, UNSET -from typing import Any, Callable, Dict, Optional, Union, cast +from typing import Any, Callable, Dict, Optional, TYPE_CHECKING, Union, cast import weakref +if TYPE_CHECKING: + from livepeer_ai.generate import Generate + class Livepeer(BaseSDK): r"""Livepeer AI Runner: An application to run AI pipelines""" - generate: Generate + generate: "Generate" + _sub_sdk_map = { + "generate": ("livepeer_ai.generate", "Generate"), + } def __init__( self, @@ -43,15 +49,19 @@ def __init__( :param retry_config: The retry configuration to use for all supported methods :param timeout_ms: Optional request timeout applied to each operation in milliseconds """ + client_supplied = True if client is None: client = httpx.Client() + client_supplied = False assert issubclass( type(client), HttpClient ), "The provided client must implement the HttpClient protocol." + async_client_supplied = True if async_client is None: async_client = httpx.AsyncClient() + async_client_supplied = False if debug_logger is None: debug_logger = get_default_logger() @@ -75,7 +85,9 @@ def __init__( self, SDKConfiguration( client=client, + client_supplied=client_supplied, async_client=async_client, + async_client_supplied=async_client_supplied, security=security, server_url=server_url, server_idx=server_idx, @@ -87,28 +99,52 @@ def __init__( hooks = SDKHooks() + # pylint: disable=protected-access + self.sdk_configuration.__dict__["_hooks"] = hooks + current_server_url, *_ = self.sdk_configuration.get_server_details() server_url, self.sdk_configuration.client = hooks.sdk_init( - current_server_url, self.sdk_configuration.client + current_server_url, client ) if current_server_url != server_url: self.sdk_configuration.server_url = server_url - # pylint: disable=protected-access - self.sdk_configuration.__dict__["_hooks"] = hooks - weakref.finalize( self, close_clients, cast(ClientOwner, self.sdk_configuration), self.sdk_configuration.client, + self.sdk_configuration.client_supplied, self.sdk_configuration.async_client, + self.sdk_configuration.async_client_supplied, ) - self._init_sdks() + def __getattr__(self, name: str): + if name in self._sub_sdk_map: + module_path, class_name = self._sub_sdk_map[name] + try: + module = importlib.import_module(module_path) + klass = getattr(module, class_name) + instance = klass(self.sdk_configuration) + setattr(self, name, instance) + return instance + except ImportError as e: + raise AttributeError( + f"Failed to import module {module_path} for attribute {name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to find class {class_name} in module {module_path} for attribute {name}: {e}" + ) from e + + raise AttributeError( + f"'{type(self).__name__}' object has no attribute '{name}'" + ) - def _init_sdks(self): - self.generate = Generate(self.sdk_configuration) + def __dir__(self): + default_attrs = list(super().__dir__()) + lazy_attrs = list(self._sub_sdk_map.keys()) + return sorted(list(set(default_attrs + lazy_attrs))) def __enter__(self): return self @@ -117,9 +153,17 @@ async def __aenter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): - if self.sdk_configuration.client is not None: + if ( + self.sdk_configuration.client is not None + and not self.sdk_configuration.client_supplied + ): self.sdk_configuration.client.close() + self.sdk_configuration.client = None async def __aexit__(self, exc_type, exc_val, exc_tb): - if self.sdk_configuration.async_client is not None: + if ( + self.sdk_configuration.async_client is not None + and not self.sdk_configuration.async_client_supplied + ): await self.sdk_configuration.async_client.aclose() + self.sdk_configuration.async_client = None diff --git a/src/livepeer_ai/sdkconfiguration.py b/src/livepeer_ai/sdkconfiguration.py index 1bdbc10..d7115a5 100644 --- a/src/livepeer_ai/sdkconfiguration.py +++ b/src/livepeer_ai/sdkconfiguration.py @@ -1,6 +1,5 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" -from ._hooks import SDKHooks from ._version import ( __gen_version__, __openapi_doc_version__, @@ -27,8 +26,10 @@ @dataclass class SDKConfiguration: - client: HttpClient - async_client: AsyncHttpClient + client: Union[HttpClient, None] + client_supplied: bool + async_client: Union[AsyncHttpClient, None] + async_client_supplied: bool debug_logger: Logger security: Optional[ Union[components.Security, Callable[[], components.Security]] @@ -43,9 +44,6 @@ class SDKConfiguration: retry_config: OptionalNullable[RetryConfig] = Field(default_factory=lambda: UNSET) timeout_ms: Optional[int] = None - def __post_init__(self): - self._hooks = SDKHooks() - def get_server_details(self) -> Tuple[str, Dict[str, str]]: if self.server_url is not None and self.server_url: return remove_suffix(self.server_url, "/"), {} @@ -53,6 +51,3 @@ def get_server_details(self) -> Tuple[str, Dict[str, str]]: self.server_idx = 0 return SERVERS[self.server_idx], {} - - def get_hooks(self) -> SDKHooks: - return self._hooks diff --git a/src/livepeer_ai/types/basemodel.py b/src/livepeer_ai/types/basemodel.py index a6187ef..231c2e3 100644 --- a/src/livepeer_ai/types/basemodel.py +++ b/src/livepeer_ai/types/basemodel.py @@ -2,7 +2,7 @@ from pydantic import ConfigDict, model_serializer from pydantic import BaseModel as PydanticBaseModel -from typing import TYPE_CHECKING, Literal, Optional, TypeVar, Union, NewType +from typing import TYPE_CHECKING, Literal, Optional, TypeVar, Union from typing_extensions import TypeAliasType, TypeAlias @@ -35,5 +35,5 @@ def __bool__(self) -> Literal[False]: "OptionalNullable", Union[Optional[Nullable[T]], Unset], type_params=(T,) ) -UnrecognizedInt = NewType("UnrecognizedInt", int) -UnrecognizedStr = NewType("UnrecognizedStr", str) +UnrecognizedInt: TypeAlias = int +UnrecognizedStr: TypeAlias = str diff --git a/src/livepeer_ai/utils/__init__.py b/src/livepeer_ai/utils/__init__.py index 26d51ae..a2fc349 100644 --- a/src/livepeer_ai/utils/__init__.py +++ b/src/livepeer_ai/utils/__init__.py @@ -1,49 +1,56 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" -from .annotations import get_discriminator -from .enums import OpenEnumMeta -from .headers import get_headers, get_response_headers -from .metadata import ( - FieldMetadata, - find_metadata, - FormMetadata, - HeaderMetadata, - MultipartFormMetadata, - PathParamMetadata, - QueryParamMetadata, - RequestMetadata, - SecurityMetadata, -) -from .queryparams import get_query_params -from .retries import BackoffStrategy, Retries, retry, retry_async, RetryConfig -from .requestbodies import serialize_request_body, SerializedRequestBody -from .security import get_security -from .serializers import ( - get_pydantic_model, - marshal_json, - unmarshal, - unmarshal_json, - serialize_decimal, - serialize_float, - serialize_int, - stream_to_text, - stream_to_text_async, - stream_to_bytes, - stream_to_bytes_async, - validate_const, - validate_decimal, - validate_float, - validate_int, - validate_open_enum, -) -from .url import generate_url, template_url, remove_suffix -from .values import ( - get_global_from_env, - match_content_type, - match_status_codes, - match_response, -) -from .logger import Logger, get_body_content, get_default_logger +from typing import TYPE_CHECKING +from importlib import import_module + +if TYPE_CHECKING: + from .annotations import get_discriminator + from .datetimes import parse_datetime + from .enums import OpenEnumMeta + from .headers import get_headers, get_response_headers + from .metadata import ( + FieldMetadata, + find_metadata, + FormMetadata, + HeaderMetadata, + MultipartFormMetadata, + PathParamMetadata, + QueryParamMetadata, + RequestMetadata, + SecurityMetadata, + ) + from .queryparams import get_query_params + from .retries import BackoffStrategy, Retries, retry, retry_async, RetryConfig + from .requestbodies import serialize_request_body, SerializedRequestBody + from .security import get_security + from .serializers import ( + get_pydantic_model, + marshal_json, + unmarshal, + unmarshal_json, + unmarshal_json_response, + serialize_decimal, + serialize_float, + serialize_int, + stream_to_text, + stream_to_text_async, + stream_to_bytes, + stream_to_bytes_async, + validate_const, + validate_decimal, + validate_float, + validate_int, + validate_open_enum, + ) + from .url import generate_url, template_url, remove_suffix + from .values import ( + get_global_from_env, + match_content_type, + match_status_codes, + match_response, + cast_partial, + ) + from .logger import Logger, get_body_content, get_default_logger __all__ = [ "BackoffStrategy", @@ -54,6 +61,7 @@ "get_body_content", "get_default_logger", "get_discriminator", + "parse_datetime", "get_global_from_env", "get_headers", "get_pydantic_model", @@ -89,9 +97,91 @@ "template_url", "unmarshal", "unmarshal_json", + "unmarshal_json_response", "validate_decimal", "validate_const", "validate_float", "validate_int", "validate_open_enum", + "cast_partial", ] + +_dynamic_imports: dict[str, str] = { + "BackoffStrategy": ".retries", + "FieldMetadata": ".metadata", + "find_metadata": ".metadata", + "FormMetadata": ".metadata", + "generate_url": ".url", + "get_body_content": ".logger", + "get_default_logger": ".logger", + "get_discriminator": ".annotations", + "parse_datetime": ".datetimes", + "get_global_from_env": ".values", + "get_headers": ".headers", + "get_pydantic_model": ".serializers", + "get_query_params": ".queryparams", + "get_response_headers": ".headers", + "get_security": ".security", + "HeaderMetadata": ".metadata", + "Logger": ".logger", + "marshal_json": ".serializers", + "match_content_type": ".values", + "match_status_codes": ".values", + "match_response": ".values", + "MultipartFormMetadata": ".metadata", + "OpenEnumMeta": ".enums", + "PathParamMetadata": ".metadata", + "QueryParamMetadata": ".metadata", + "remove_suffix": ".url", + "Retries": ".retries", + "retry": ".retries", + "retry_async": ".retries", + "RetryConfig": ".retries", + "RequestMetadata": ".metadata", + "SecurityMetadata": ".metadata", + "serialize_decimal": ".serializers", + "serialize_float": ".serializers", + "serialize_int": ".serializers", + "serialize_request_body": ".requestbodies", + "SerializedRequestBody": ".requestbodies", + "stream_to_text": ".serializers", + "stream_to_text_async": ".serializers", + "stream_to_bytes": ".serializers", + "stream_to_bytes_async": ".serializers", + "template_url": ".url", + "unmarshal": ".serializers", + "unmarshal_json": ".serializers", + "unmarshal_json_response": ".serializers", + "validate_decimal": ".serializers", + "validate_const": ".serializers", + "validate_float": ".serializers", + "validate_int": ".serializers", + "validate_open_enum": ".serializers", + "cast_partial": ".values", +} + + +def __getattr__(attr_name: str) -> object: + module_name = _dynamic_imports.get(attr_name) + if module_name is None: + raise AttributeError( + f"no {attr_name} found in _dynamic_imports, module name -> {__name__} " + ) + + try: + module = import_module(module_name, __package__) + result = getattr(module, attr_name) + return result + except ImportError as e: + raise ImportError( + f"Failed to import {attr_name} from {module_name}: {e}" + ) from e + except AttributeError as e: + raise AttributeError( + f"Failed to get {attr_name} from {module_name}: {e}" + ) from e + + +def __dir__(): + lazy_attrs = list(_dynamic_imports.keys()) + return sorted(lazy_attrs) diff --git a/src/livepeer_ai/utils/datetimes.py b/src/livepeer_ai/utils/datetimes.py new file mode 100644 index 0000000..a6c52cd --- /dev/null +++ b/src/livepeer_ai/utils/datetimes.py @@ -0,0 +1,23 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from datetime import datetime +import sys + + +def parse_datetime(datetime_string: str) -> datetime: + """ + Convert a RFC 3339 / ISO 8601 formatted string into a datetime object. + Python versions 3.11 and later support parsing RFC 3339 directly with + datetime.fromisoformat(), but for earlier versions, this function + encapsulates the necessary extra logic. + """ + # Python 3.11 and later can parse RFC 3339 directly + if sys.version_info >= (3, 11): + return datetime.fromisoformat(datetime_string) + + # For Python 3.10 and earlier, a common ValueError is trailing 'Z' suffix, + # so fix that upfront. + if datetime_string.endswith("Z"): + datetime_string = datetime_string[:-1] + "+00:00" + + return datetime.fromisoformat(datetime_string) diff --git a/src/livepeer_ai/utils/enums.py b/src/livepeer_ai/utils/enums.py index c650b10..c3bc13c 100644 --- a/src/livepeer_ai/utils/enums.py +++ b/src/livepeer_ai/utils/enums.py @@ -1,34 +1,74 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" import enum - +import sys class OpenEnumMeta(enum.EnumMeta): - def __call__( - cls, value, names=None, *, module=None, qualname=None, type=None, start=1 - ): - # The `type` kwarg also happens to be a built-in that pylint flags as - # redeclared. Safe to ignore this lint rule with this scope. - # pylint: disable=redefined-builtin + # The __call__ method `boundary` kwarg was added in 3.11 and must be present + # for pyright. Refer also: https://github.com/pylint-dev/pylint/issues/9622 + # pylint: disable=unexpected-keyword-arg + # The __call__ method `values` varg must be named for pyright. + # pylint: disable=keyword-arg-before-vararg + + if sys.version_info >= (3, 11): + def __call__( + cls, value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None + ): + # The `type` kwarg also happens to be a built-in that pylint flags as + # redeclared. Safe to ignore this lint rule with this scope. + # pylint: disable=redefined-builtin + + if names is not None: + return super().__call__( + value, + names=names, + *values, + module=module, + qualname=qualname, + type=type, + start=start, + boundary=boundary, + ) + + try: + return super().__call__( + value, + names=names, # pyright: ignore[reportArgumentType] + *values, + module=module, + qualname=qualname, + type=type, + start=start, + boundary=boundary, + ) + except ValueError: + return value + else: + def __call__( + cls, value, names=None, *, module=None, qualname=None, type=None, start=1 + ): + # The `type` kwarg also happens to be a built-in that pylint flags as + # redeclared. Safe to ignore this lint rule with this scope. + # pylint: disable=redefined-builtin - if names is not None: - return super().__call__( - value, - names=names, - module=module, - qualname=qualname, - type=type, - start=start, - ) + if names is not None: + return super().__call__( + value, + names=names, + module=module, + qualname=qualname, + type=type, + start=start, + ) - try: - return super().__call__( - value, - names=names, # pyright: ignore[reportArgumentType] - module=module, - qualname=qualname, - type=type, - start=start, - ) - except ValueError: - return value + try: + return super().__call__( + value, + names=names, # pyright: ignore[reportArgumentType] + module=module, + qualname=qualname, + type=type, + start=start, + ) + except ValueError: + return value diff --git a/src/livepeer_ai/utils/forms.py b/src/livepeer_ai/utils/forms.py index 0472aba..e873495 100644 --- a/src/livepeer_ai/utils/forms.py +++ b/src/livepeer_ai/utils/forms.py @@ -86,11 +86,39 @@ def _populate_form( return form +def _extract_file_properties(file_obj: Any) -> Tuple[str, Any, Any]: + """Extract file name, content, and content type from a file object.""" + file_fields: Dict[str, FieldInfo] = file_obj.__class__.model_fields + + file_name = "" + content = None + content_type = None + + for file_field_name in file_fields: + file_field = file_fields[file_field_name] + + file_metadata = find_field_metadata(file_field, MultipartFormMetadata) + if file_metadata is None: + continue + + if file_metadata.content: + content = getattr(file_obj, file_field_name, None) + elif file_field_name == "content_type": + content_type = getattr(file_obj, file_field_name, None) + else: + file_name = getattr(file_obj, file_field_name) + + if file_name == "" or content is None: + raise ValueError("invalid multipart/form-data file") + + return file_name, content, content_type + + def serialize_multipart_form( media_type: str, request: Any -) -> Tuple[str, Dict[str, Any], Dict[str, Any]]: +) -> Tuple[str, Dict[str, Any], List[Tuple[str, Any]]]: form: Dict[str, Any] = {} - files: Dict[str, Any] = {} + files: List[Tuple[str, Any]] = [] if not isinstance(request, BaseModel): raise TypeError("invalid request body type") @@ -112,39 +140,32 @@ def serialize_multipart_form( f_name = field.alias if field.alias else name if field_metadata.file: - file_fields: Dict[str, FieldInfo] = val.__class__.model_fields - - file_name = "" - content = None - content_type = None - - for file_field_name in file_fields: - file_field = file_fields[file_field_name] + if isinstance(val, List): + # Handle array of files + for file_obj in val: + if not _is_set(file_obj): + continue + + file_name, content, content_type = _extract_file_properties(file_obj) - file_metadata = find_field_metadata(file_field, MultipartFormMetadata) - if file_metadata is None: - continue + if content_type is not None: + files.append((f_name + "[]", (file_name, content, content_type))) + else: + files.append((f_name + "[]", (file_name, content))) + else: + # Handle single file + file_name, content, content_type = _extract_file_properties(val) - if file_metadata.content: - content = getattr(val, file_field_name, None) - elif file_field_name == "content_type": - content_type = getattr(val, file_field_name, None) + if content_type is not None: + files.append((f_name, (file_name, content, content_type))) else: - file_name = getattr(val, file_field_name) - - if file_name == "" or content is None: - raise ValueError("invalid multipart/form-data file") - - if content_type is not None: - files[f_name] = (file_name, content, content_type) - else: - files[f_name] = (file_name, content) + files.append((f_name, (file_name, content))) elif field_metadata.json: - files[f_name] = ( + files.append((f_name, ( None, marshal_json(val, request_field_types[name]), "application/json", - ) + ))) else: if isinstance(val, List): values = [] diff --git a/src/livepeer_ai/utils/serializers.py b/src/livepeer_ai/utils/serializers.py index c5eb365..773203d 100644 --- a/src/livepeer_ai/utils/serializers.py +++ b/src/livepeer_ai/utils/serializers.py @@ -1,20 +1,25 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" from decimal import Decimal +import functools import json -from typing import Any, Dict, List, Union, get_args -import httpx +import typing +from typing import Any, Dict, List, Optional, Tuple, Union, get_args +import typing_extensions from typing_extensions import get_origin + +import httpx from pydantic import ConfigDict, create_model from pydantic_core import from_json -from typing_inspect import is_optional_type from ..types.basemodel import BaseModel, Nullable, OptionalNullable, Unset +from livepeer_ai.models import errors def serialize_decimal(as_str: bool): def serialize(d): - if is_optional_type(type(d)) and d is None: + # Optional[T] is a Union[T, None] + if is_union(type(d)) and type(None) in get_args(type(d)) and d is None: return None if isinstance(d, Unset): return d @@ -42,7 +47,8 @@ def validate_decimal(d): def serialize_float(as_str: bool): def serialize(f): - if is_optional_type(type(f)) and f is None: + # Optional[T] is a Union[T, None] + if is_union(type(f)) and type(None) in get_args(type(f)) and f is None: return None if isinstance(f, Unset): return f @@ -70,7 +76,8 @@ def validate_float(f): def serialize_int(as_str: bool): def serialize(i): - if is_optional_type(type(i)) and i is None: + # Optional[T] is a Union[T, None] + if is_union(type(i)) and type(None) in get_args(type(i)) and i is None: return None if isinstance(i, Unset): return i @@ -118,7 +125,8 @@ def validate(e): def validate_const(v): def validate(c): - if is_optional_type(type(c)) and c is None: + # Optional[T] is a Union[T, None] + if is_union(type(c)) and type(None) in get_args(type(c)) and c is None: return None if v != c: @@ -133,6 +141,22 @@ def unmarshal_json(raw, typ: Any) -> Any: return unmarshal(from_json(raw), typ) +def unmarshal_json_response( + typ: Any, http_res: httpx.Response, body: Optional[str] = None +) -> Any: + if body is None: + body = http_res.text + try: + return unmarshal_json(body, typ) + except Exception as e: + raise errors.ResponseValidationError( + "Response validation failed", + http_res, + e, + body, + ) from e + + def unmarshal(val, typ: Any) -> Any: unmarshaller = create_model( "Unmarshaller", @@ -163,7 +187,7 @@ def marshal_json(val, typ): if len(d) == 0: return "" - return json.dumps(d[next(iter(d))], separators=(",", ":"), sort_keys=True) + return json.dumps(d[next(iter(d))], separators=(",", ":")) def is_nullable(field): @@ -181,6 +205,15 @@ def is_nullable(field): return False +def is_union(obj: object) -> bool: + """ + Returns True if the given object is a typing.Union or typing_extensions.Union. + """ + return any( + obj is typing_obj for typing_obj in _get_typing_objects_by_name_of("Union") + ) + + def stream_to_text(stream: httpx.Response) -> str: return "".join(stream.iter_text()) @@ -213,3 +246,21 @@ def _contains_pydantic_model(data: Any) -> bool: return any(_contains_pydantic_model(value) for value in data.values()) return False + + +@functools.cache +def _get_typing_objects_by_name_of(name: str) -> Tuple[Any, ...]: + """ + Get typing objects by name from typing and typing_extensions. + Reference: https://typing-extensions.readthedocs.io/en/latest/#runtime-use-of-types + """ + result = tuple( + getattr(module, name) + for module in (typing, typing_extensions) + if hasattr(module, name) + ) + if not result: + raise ValueError( + f"Neither typing nor typing_extensions has an object called {name!r}" + ) + return result diff --git a/src/livepeer_ai/utils/values.py b/src/livepeer_ai/utils/values.py index 2b4b683..dae01a4 100644 --- a/src/livepeer_ai/utils/values.py +++ b/src/livepeer_ai/utils/values.py @@ -3,8 +3,9 @@ from datetime import datetime from enum import Enum from email.message import Message +from functools import partial import os -from typing import Any, Callable, Dict, List, Optional, Tuple, TypeVar, Union +from typing import Any, Callable, Dict, List, Optional, Tuple, TypeVar, Union, cast from httpx import Response from pydantic import BaseModel @@ -51,6 +52,8 @@ def match_status_codes(status_codes: List[str], status_code: int) -> bool: T = TypeVar("T") +def cast_partial(typ): + return partial(cast, typ) def get_global_from_env( value: Optional[T], env_key: str, type_cast: Callable[[str], T]