diff --git a/.devcontainer/README.md b/.devcontainer/README.md
index 396929a..a400f2a 100644
--- a/.devcontainer/README.md
+++ b/.devcontainer/README.md
@@ -1,4 +1,9 @@
+
+

+
+
+
> **Remember to shutdown a GitHub Codespace when it is not in use!**
# Dev Containers Quick Start
diff --git a/.gitignore b/.gitignore
index aedee07..ce43896 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+.env
+.env.local
.venv/
venv/
src/*.egg-info/
diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock
index 4c60bf7..a3c1657 100644
--- a/.speakeasy/gen.lock
+++ b/.speakeasy/gen.lock
@@ -1,25 +1,26 @@
lockVersion: 2.0.0
id: a559c4f4-5ced-4888-977e-9da6df24ea1e
management:
- docChecksum: 1b6f1e0e724a103c5bafac828edf515a
+ docChecksum: 5be1033d3fcd17c8b64f613200c1ef01
docVersion: 1.0.0
- speakeasyVersion: 1.606.3
- generationVersion: 2.687.1
- releaseVersion: 0.0.2
- configChecksum: 3cb87fb1854fe2e2685bcb6699703b19
+ speakeasyVersion: 1.621.0
+ generationVersion: 2.707.0
+ releaseVersion: 0.1.0
+ configChecksum: e02e2d791f75a4bfe768d682325c2131
+ repoURL: https://github.com/QuePlatform/PythonSDK.git
+ installationURL: https://github.com/QuePlatform/PythonSDK.git
+ published: true
features:
python:
additionalDependencies: 1.0.0
- additionalProperties: 1.0.1
constsAndDefaults: 1.0.5
- core: 5.19.9
+ core: 5.20.4
defaultEnabledRetries: 0.2.0
- deprecations: 3.0.2
devContainers: 3.0.0
enumUnions: 0.1.0
envVarSecurityUsage: 0.3.2
flatRequests: 1.0.1
- globalSecurity: 3.0.3
+ globalSecurity: 3.0.4
globalSecurityCallbacks: 1.0.0
globalSecurityFlattening: 1.0.0
globalServerURLs: 3.1.1
@@ -37,32 +38,43 @@ generatedFiles:
- .vscode/settings.json
- USAGE.md
- docs/errors/problemresponseerror.md
+ - docs/models/alg.md
- docs/models/assetrefdto.md
- - docs/models/bytesbase64.md
+ - docs/models/assurance.md
+ - docs/models/cawgidentitydto.md
+ - docs/models/cawgverifydto.md
- docs/models/data.md
+ - docs/models/default.md
- docs/models/details.md
- docs/models/evidence.md
- docs/models/getpresignedurlresponse.md
- docs/models/gettrustlistresponse.md
- docs/models/healthzresponse.md
- - docs/models/manifestjson.md
+ - docs/models/limitsdto.md
+ - docs/models/mode.md
- docs/models/policy.md
- docs/models/presignedurl.md
- docs/models/presignresponse.md
- docs/models/s3.md
- docs/models/security.md
- docs/models/signassetresponse.md
+ - docs/models/signer.md
+ - docs/models/signerrefdto.md
+ - docs/models/signerrefdtoenv.md
+ - docs/models/signerrefdtolocal.md
+ - docs/models/signerseparate.md
+ - docs/models/signerusemainsigner.md
+ - docs/models/signingalg.md
- docs/models/signrequest.md
- - docs/models/signrequestmode.md
- docs/models/signresponse.md
- - docs/models/summary.md
- docs/models/trustlistresponse.md
+ - docs/models/typeenv.md
+ - docs/models/typelocal.md
+ - docs/models/typeseparate.md
+ - docs/models/typeusemainsigner.md
- docs/models/utils/retryconfig.md
- - docs/models/validationstatus.md
- - docs/models/verificationreport.md
- docs/models/verifyassetresponse.md
- docs/models/verifyrequest.md
- - docs/models/verifyrequestmode.md
- docs/models/verifyresponse.md
- docs/sdks/assetmanagement/README.md
- docs/sdks/que/README.md
@@ -70,6 +82,7 @@ generatedFiles:
- py.typed
- pylintrc
- pyproject.toml
+ - scripts/prepare_readme.py
- scripts/publish.sh
- src/que_media/__init__.py
- src/que_media/_hooks/__init__.py
@@ -87,20 +100,22 @@ generatedFiles:
- src/que_media/httpclient.py
- src/que_media/models/__init__.py
- src/que_media/models/assetrefdto.py
- - src/que_media/models/bytesbase64.py
+ - src/que_media/models/cawgidentitydto.py
+ - src/que_media/models/cawgverifydto.py
- src/que_media/models/getpresignedurlop.py
- src/que_media/models/gettrustlistop.py
- src/que_media/models/healthzresponse.py
+ - src/que_media/models/limitsdto.py
- src/que_media/models/presignedurl.py
- src/que_media/models/presignresponse.py
- src/que_media/models/problemresponse_error.py
- src/que_media/models/s3.py
- src/que_media/models/security.py
- src/que_media/models/signassetop.py
+ - src/que_media/models/signerrefdto.py
- src/que_media/models/signrequest.py
- src/que_media/models/signresponse.py
- src/que_media/models/trustlistresponse.py
- - src/que_media/models/verificationreport.py
- src/que_media/models/verifyassetop.py
- src/que_media/models/verifyrequest.py
- src/que_media/models/verifyresponse.py
@@ -131,10 +146,34 @@ examples:
verifyAsset:
speakeasy-default-verify-asset:
requestBody:
- application/json: {"asset": {"url": "https://example.com/images/provenance-image.jpg"}, "mode": "detailed"}
+ application/json: {"asset": {"url": "https://example.com/images/provenance-image.jpg"}, "mode": "detailed", "allow_remote_manifests": false, "allow_insecure_remote_http": false, "include_certificates": true, "limits": {"max_asset_size_bytes": 104857600, "max_output_size_bytes": 104857600, "max_stream_copy_bytes": 104857600, "stream_timeout_ms": 30000}}
responses:
"200":
- application/json: {"report": {"report": {"validationStatus": [{"code": "claim.signature.validated", "explanation": "Claim signature validated"}], "summary": {"isTrusted": true, "signer": "CN=Que Signing Service"}}}}
+ application/json: {"report": ""}
+ "400":
+ application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
+ "429":
+ application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
+ "500":
+ application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
+ basic-verification:
+ requestBody:
+ application/json: {"asset": {"bucket": "que-assets-dev", "key": "uploads/photo.jpg"}, "mode": "summary", "allow_remote_manifests": false, "allow_insecure_remote_http": false, "include_certificates": true}
+ responses:
+ "200":
+ application/json: {"report": ""}
+ "400":
+ application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
+ "429":
+ application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
+ "500":
+ application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
+ detailed-verification:
+ requestBody:
+ application/json: {"asset": {"bucket": "que-assets-dev", "key": "uploads/document.pdf"}, "mode": "detailed", "allow_remote_manifests": true, "allow_insecure_remote_http": false, "include_certificates": true, "limits": {"max_asset_size_bytes": 52428800}}
+ responses:
+ "200":
+ application/json: {"report": ""}
"400":
application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
"429":
@@ -144,10 +183,34 @@ examples:
signAsset:
speakeasy-default-sign-asset:
requestBody:
- application/json: {"asset": {"b64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="}, "mode": "server_measure", "manifest_json": {}}
+ application/json: {"asset": {"bucket": "que-assets-dev", "key": "uploads/user123/asset.jpg"}, "mode": "server_measure", "manifest_json": "{\"title\":\"Original Photograph\",\"format\":\"image/jpeg\",\"assertions\":[{\"label\":\"stds.schema-org.CreativeWork\",\"data\":{\"@context\":\"https://schema.org\",\"@type\":\"CreativeWork\",\"author\":[{\"@type\":\"Person\",\"name\":\"Jane Photographer\"}]}}]}", "allow_insecure_remote_http": false, "limits": {"max_asset_size_bytes": 104857600, "max_output_size_bytes": 104857600, "max_stream_copy_bytes": 104857600, "stream_timeout_ms": 30000}}
+ responses:
+ "200":
+ application/json: {"assurance": "server_measured", "evidence": {"signer": "env_dev", "alg": "ES256"}, "asset_s3_uri": "s3://que-signed-assets/uuid/signed.jpg"}
+ "400":
+ application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
+ "429":
+ application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
+ "500":
+ application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
+ basic-signing:
+ requestBody:
+ application/json: {"asset": {"bucket": "que-assets-dev", "key": "uploads/photo.jpg"}, "mode": "server_measure", "manifest_json": "{\"title\":\"Original Photograph\",\"assertions\":[{\"label\":\"stds.schema-org.CreativeWork\",\"data\":{\"@context\":\"https://schema.org\",\"@type\":\"CreativeWork\",\"author\":[{\"@type\":\"Person\",\"name\":\"Jane Photographer\"}]}}]}", "allow_insecure_remote_http": false}
+ responses:
+ "200":
+ application/json: {"assurance": "server_measured", "evidence": {"signer": "env_dev", "alg": "ES256"}, "asset_s3_uri": "s3://que-signed-assets/uuid/signed.jpg"}
+ "400":
+ application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
+ "429":
+ application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
+ "500":
+ application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
+ advanced-signing:
+ requestBody:
+ application/json: {"asset": {"bucket": "que-assets-dev", "key": "uploads/document.pdf"}, "mode": "server_measure", "manifest_json": "{\"title\":\"Signed Document\",\"assertions\":[{\"label\":\"stds.schema-org.CreativeWork\",\"data\":{\"@context\":\"https://schema.org\",\"@type\":\"CreativeWork\",\"author\":[{\"@type\":\"Person\",\"name\":\"John Author\"}]}}]}", "allow_insecure_remote_http": false, "limits": {"max_asset_size_bytes": 104857600, "stream_timeout_ms": 60000}}
responses:
"200":
- application/json: {"assurance": "server_measured", "evidence": {}, "asset_s3_uri": "s3://Que-signed-assets/a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8/signed.jpg"}
+ application/json: {"assurance": "server_measured", "evidence": {"signer": "env_dev", "alg": "ES256"}, "asset_s3_uri": "s3://que-signed-assets/uuid/signed.jpg"}
"400":
application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
"429":
@@ -163,7 +226,7 @@ examples:
speakeasy-default-get-trust-list:
responses:
"200":
- application/json: {"version": "prod-2025-08-15", "issued_at": "2025-08-15T20:00:00Z", "data": {"manufacturers": ["Example Camera Corp"], "cas": ["-----BEGIN CERTIFICATE-----\nMIID...=\n-----END CERTIFICATE-----"], "policy": {"default": "allow"}}}
+ application/json: {"version": "dev-1", "issued_at": "2024-01-15T10:00:00Z", "data": {"manufacturers": [], "cas": [], "policy": {"default": "allow"}}}
"401":
application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
"429":
@@ -174,7 +237,7 @@ examples:
speakeasy-default-get-presigned-url:
responses:
"200":
- application/json: {"url": "https://Que-customer-uploads.s3.amazonaws.com/new-asset-key?AWSAccessKeyId=...", "key": "uploads/user123/timestamp/asset.jpg"}
+ application/json: {"url": "https://que-assets-dev.s3.us-east-2.amazonaws.com/uploads/user123/asset.jpg?AWSAccessKeyId=...&Signature=...&Expires=...", "key": "uploads/user123/asset.jpg"}
"401":
application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
"429":
@@ -182,3 +245,4 @@ examples:
"500":
application/problem+json: {"type": "about:blank", "title": "rate_limited", "status": 429, "code": "rate_limited", "detail": "try again in 5000 ms", "details": {}}
examplesVersion: 1.0.2
+releaseNotes: "## Python SDK Changes Detected:\n* `que.verify_asset()`: \n * `request` **Changed** **Breaking** :warning:\n * `response.report` **Changed** **Breaking** :warning:\n* `que.sign_asset()`: \n * `request` **Changed** **Breaking** :warning:\n * `response` **Changed** **Breaking** :warning:\n* `que.utility.get_trust_list()`: `response.data.policy.default` **Changed** **Breaking** :warning:\n"
diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml
index f41a635..f3e9cee 100644
--- a/.speakeasy/gen.yaml
+++ b/.speakeasy/gen.yaml
@@ -17,18 +17,22 @@ generation:
securityFeb2025: true
sharedErrorComponentsApr2025: true
auth:
- oAuth2ClientCredentialsEnabled: true
- oAuth2PasswordEnabled: true
+ oAuth2ClientCredentialsEnabled: false
+ oAuth2PasswordEnabled: false
+ hoistGlobalSecurity: true
sdkHooksConfigAccess: true
tests:
generateTests: false
generateNewTests: true
skipResponseBodyAssertions: false
python:
- version: 0.0.2
+ version: 0.1.0
additionalDependencies:
dev: {}
main: {}
+ allowedRedefinedBuiltins:
+ - id
+ - object
authors:
- Speakeasy
baseErrorName: QueError
@@ -61,4 +65,5 @@ python:
pytestFilterWarnings: []
pytestTimeout: 0
responseFormat: flat
+ sseFlatResponse: false
templateVersion: v2
diff --git a/.speakeasy/out.openapi.yaml b/.speakeasy/out.openapi.yaml
index c57c3ed..9869ef0 100644
--- a/.speakeasy/out.openapi.yaml
+++ b/.speakeasy/out.openapi.yaml
@@ -3,16 +3,23 @@ info:
title: Que API
version: "1.0.0"
description: |
- Welcome to the Que Public HTTP API. Our platform provides robust tools for working with C2PA (Coalition for Content Provenance and Authenticity) manifests, enabling you to sign and verify digital assets to ensure their authenticity and provenance.
+ Welcome to the Que Public HTTP API for C2PA (Content Authenticity Initiative) provenance management.
+
+ Our platform provides robust tools for working with digital asset provenance through C2PA manifests, enabling you to sign and verify digital assets to ensure their authenticity, origin, and processing history.
**Key Features:**
- * **Verify**: Inspect and validate C2PA manifests embedded in assets.
- * **Sign**: Embed C2PA manifests into your assets with a server-side signature.
- * **Trust Management**: Retrieve the current C2PA trust list.
+ * **Memory-Efficient Streaming**: Assets are processed using streaming techniques to minimize memory usage, supporting large files efficiently
+ * **Verify**: Inspect and validate C2PA manifests embedded in assets with multiple detail levels
+ * **Sign**: Embed comprehensive C2PA manifests into your assets with server-side cryptographic signatures
+ * **Trust Management**: Retrieve and validate against current trust lists containing trusted certificate authorities and manufacturers
+ * **Secure Uploads**: Direct-to-S3 uploads via presigned URLs for large assets
**Authentication:**
All endpoints (except for `/healthz`) are secured and require an API key to be passed in the `x-api-key` header.
+ **Processing Architecture:**
+ Assets are streamed from S3 or URLs to temporary storage during processing to ensure O(chunk_size) memory usage instead of O(file_size), enabling efficient handling of large files on containerized platforms.
+
Usage of this API is tracked via Firehose for billing and monitoring purposes.
contact:
name: Que API Support
@@ -96,7 +103,7 @@ components:
detail: "resource not found"
UnprocessableEntity:
- description: Unprocessable Entity. The request was valid but could not be processed (e.g., C2PA verification failed).
+ description: Unprocessable Entity. The request was valid but could not be processed (e.g., verification failed).
content:
application/problem+json:
schema:
@@ -111,13 +118,13 @@ components:
code: "engine_verification"
detail: "verification failed"
c2pa_error:
- summary: C2PA processing error
+ summary: Processing error
value:
type: "about:blank"
title: "root operation failed"
status: 422
code: "engine_c2pa"
- detail: "c2pa: unsupported manifest format"
+ detail: "Unsupported manifest format"
RateLimited:
description: Too Many Requests. The client has exceeded the allowed request rate.
@@ -254,119 +261,201 @@ components:
- message
- timestamp
- # ----- AssetRefDto variants -----
- AssetRefDto:
- description: A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object.
- oneOf:
- - $ref: "#/components/schemas/BytesBase64"
- - $ref: "#/components/schemas/PresignedUrl"
- - $ref: "#/components/schemas/S3"
-
- BytesBase64:
+ LimitsDto:
type: object
- description: An asset provided as a Base64-encoded string. Suitable for small files.
+ description: Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling.
properties:
- b64:
- type: string
- description: The raw bytes of the asset, encoded in Base64.
- example: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="
- required:
- - b64
+ max_asset_size_bytes:
+ type: integer
+ format: int64
+ description: Maximum allowed size for the asset file in bytes. This limit is enforced during the streaming download phase to prevent memory exhaustion.
+ example: 104857600
+ minimum: 1
+ maximum: 1073741824
+ max_output_size_bytes:
+ type: integer
+ format: int64
+ description: Maximum allowed size for the output (signed asset) in bytes. This prevents excessive storage usage for signed assets.
+ example: 104857600
+ minimum: 1
+ maximum: 1073741824
+ max_stream_copy_bytes:
+ type: integer
+ format: int64
+ description: Maximum allowed bytes for stream copying operations during processing. This limits the amount of data that can be buffered in memory during the signing/verification process.
+ example: 104857600
+ minimum: 1
+ maximum: 1073741824
+ stream_timeout_ms:
+ type: integer
+ format: int64
+ description: Timeout for streaming operations in milliseconds. This prevents hanging operations when downloading from slow sources.
+ example: 30000
+ minimum: 1000
+ maximum: 300000
- PresignedUrl:
+ # ----- CAWG Schemas -----
+ CawgVerifyDto:
type: object
- description: An asset located at a publicly accessible or presigned URL.
+ description: Options controlling CAWG identity validation behavior during verification.
properties:
- url:
+ validate:
+ type: boolean
+ description: Whether to run CAWG identity validation.
+ default: true
+ require_valid_identity:
+ type: boolean
+ description: Whether to fail verification if CAWG identity is missing/invalid.
+ default: false
+
+ CawgIdentityDto:
+ type: object
+ description: Configuration to add a CAWG identity assertion during signing. Presence of this object enables CAWG.
+ properties:
+ signer:
+ oneOf:
+ - type: object
+ properties:
+ type:
+ type: string
+ enum: [use_main_signer]
+ required: [type]
+ - type: object
+ properties:
+ type:
+ type: string
+ enum: [separate]
+ signer:
+ $ref: "#/components/schemas/SignerRefDto"
+ required: [type, signer]
+ signing_alg:
type: string
- format: uri
- description: The URL where the asset can be downloaded.
- example: "https://my-public-bucket.s3.amazonaws.com/assets/image.jpg?AWSAccessKeyId=..."
- required:
- - url
+ description: Algorithm used for the CAWG identity signature.
+ enum: [ed25519, es256, es384, ps256]
+ default: ed25519
+ referenced_assertions:
+ type: array
+ items:
+ type: string
+ description: Assertion labels that the identity assertion should reference.
+ default: ["c2pa.actions"]
+ timestamper:
+ type: string
+ description: Timestamper to use ("digicert" or "custom:").
+
+ SignerRefDto:
+ type: object
+ description: Reference to credentials for signing.
+ oneOf:
+ - type: object
+ properties:
+ type:
+ type: string
+ enum: [env]
+ cert_var:
+ type: string
+ key_var:
+ type: string
+ required: [type, cert_var, key_var]
+ - type: object
+ properties:
+ type:
+ type: string
+ enum: [local]
+ cert_path:
+ type: string
+ key_path:
+ type: string
+ required: [type, cert_path, key_path]
+
+ # ----- AssetRefDto (S3 and URL support) -----
+ AssetRefDto:
+ description: A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage.
+ oneOf:
+ - $ref: "#/components/schemas/S3"
+ - $ref: "#/components/schemas/PresignedUrl"
S3:
type: object
- description: An asset located in an S3 bucket that the Que service has access to.
+ description: An asset located in an S3 bucket that the Que service has access to. The service will stream the file from S3 to temporary storage during processing.
properties:
bucket:
type: string
description: The name of the S3 bucket.
- example: "Que-customer-assets"
+ example: "que-assets-dev"
key:
type: string
description: The object key (path) within the S3 bucket.
- example: "uploads/user123/original.png"
+ example: "uploads/user123/asset.jpg"
required:
- bucket
- key
+ PresignedUrl:
+ type: object
+ description: An asset accessible via HTTP/HTTPS URL. The URL must be enabled via the ALLOW_URL_ASSETS environment variable. The service will stream the file to temporary storage during processing.
+ properties:
+ url:
+ type: string
+ format: uri
+ description: The HTTP/HTTPS URL of the asset. Must be publicly accessible.
+ example: "https://example.com/assets/photo.jpg"
+ required:
+ - url
+
# ----- /v1/verify -----
VerifyRequest:
type: object
+ description: Request to verify the C2PA manifest embedded in a digital asset. The asset is processed using memory-efficient streaming to temporary storage.
properties:
asset:
$ref: "#/components/schemas/AssetRefDto"
mode:
type: string
default: "summary"
- enum:
- - info
- - detailed
- - tree
- - summary
description: |
The level of detail to return in the verification report.
- * `summary`: A high-level pass/fail result. Fastest option.
- * `info`: Basic information about the manifest and its claims.
- * `detailed`: In-depth details of all assertions and claims.
- * `tree`: A hierarchical view of the manifest's ingredient relationships.
+ * `summary`: A high-level pass/fail result with basic trust status. Fastest option for simple validation.
+ * `info`: Basic information about the manifest, claims, and signing entities.
+ * `detailed`: Comprehensive details of all assertions, claims, signatures, and validation steps.
+ * `tree`: Hierarchical view of the manifest's ingredient relationships and provenance chain.
+ example: "detailed"
+ allow_remote_manifests:
+ type: boolean
+ description: Whether to allow fetching and validating remote manifests referenced in the asset's C2PA data.
+ default: false
+ example: false
+ allow_insecure_remote_http:
+ type: boolean
+ description: Whether to allow HTTP (non-HTTPS) URLs when fetching remote manifest resources. Disabled by default for security.
+ default: false
+ example: false
+ include_certificates:
+ type: boolean
+ description: Whether to include full certificate chains and cryptographic details in the verification report.
+ default: false
+ example: true
+ cawg:
+ $ref: "#/components/schemas/CawgVerifyDto"
+ limits:
+ $ref: "#/components/schemas/LimitsDto"
required:
- asset
- example:
- asset:
- url: "https://example.com/images/provenance-image.jpg"
- mode: "detailed"
VerifyResponse:
type: object
+ description: The result of a C2PA manifest verification operation.
properties:
report:
- $ref: "#/components/schemas/VerificationReport"
+ type: string
+ description: JSON string containing the verification report from the C2PA engine. The structure varies based on the verification mode requested.
required:
- report
- VerificationReport:
- type: object
- properties:
- validationStatus:
- type: array
- items:
- type: object
- properties:
- code:
- type: string
- explanation:
- type: string
- summary:
- type: object
- properties:
- isTrusted:
- type: boolean
- signer:
- type: string
- additionalProperties: true
- example:
- report:
- validationStatus:
- - code: "claim.signature.validated"
- explanation: "Claim signature validated"
- summary:
- isTrusted: true
- signer: "CN=Que Signing Service"
# ----- /v1/sign -----
SignRequest:
type: object
+ description: Request to sign a digital asset with a C2PA manifest. The asset is processed using memory-efficient streaming to temporary storage.
properties:
asset:
$ref: "#/components/schemas/AssetRefDto"
@@ -377,54 +466,63 @@ components:
- client_hash
description: |
The signing mode to use.
- * `server_measure`: The server will download the asset, calculate its hash, and embed the manifest. Requires `manifest_json`.
- * `client_hash`: The client provides the asset hash directly. (Not yet implemented).
- deprecated: true
+ * `server_measure`: The server streams the asset, calculates its hash, and embeds the manifest. Requires `manifest_json`. This is the primary signing mode.
+ * `client_hash`: The client provides the asset hash directly for offline signing. (Not yet implemented).
+ example: "server_measure"
manifest_json:
- type: object
- description: The C2PA manifest to embed in the asset. This is required when `mode` is `server_measure`.
+ type: string
+ description: JSON string containing the manifest to embed in the asset as a C2PA claim. This defines the provenance information and assertions about the asset. Required when `mode` is `server_measure`.
+ example: "{\"title\":\"Original Photograph\",\"format\":\"image/jpeg\",\"assertions\":[{\"label\":\"stds.schema-org.CreativeWork\",\"data\":{\"@context\":\"https://schema.org\",\"@type\":\"CreativeWork\",\"author\":[{\"@type\":\"Person\",\"name\":\"Jane Photographer\"}]}}]}"
+ cawg:
+ $ref: "#/components/schemas/CawgIdentityDto"
+ allow_insecure_remote_http:
+ type: boolean
+ description: Whether to allow HTTP (non-HTTPS) URLs for remote manifest resources. Disabled by default for security.
+ default: false
+ example: false
+ limits:
+ $ref: "#/components/schemas/LimitsDto"
required:
- asset
- mode
- example:
- asset:
- b64: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="
- mode: "server_measure"
- manifest_json:
- alg: "ps256"
- ta_url: "http://timestamp.digicert.com"
- assertions:
- - label: "stds.schema-org.CreativeWork"
- data:
- "@context": "https://schema.org"
- "@type": "CreativeWork"
- "author":
- - "@type": "Person"
- "name": "John Doe"
SignResponse:
type: object
- description: The result of a successful signing operation, including the signed asset.
+ description: The result of a successful signing operation. The signed asset is stored in S3 and the manifest is cryptographically embedded.
properties:
assurance:
type: string
description: The level of assurance provided by the signing process.
+ enum:
+ - server_measured
+ - client_hash
example: "server_measured"
evidence:
type: object
- description: Metadata about the signature that was applied.
- example:
- signer: "env_dev"
- alg: "ES256"
- asset_b64:
- type: string
- nullable: true
- description: The Base64-encoded signed asset. This field is populated if the resulting asset is 3MB or less. If larger, this will be null.
+ description: Cryptographic evidence about the signature that was applied.
+ properties:
+ signer:
+ type: string
+ description: Identifier for the signing entity/key used.
+ example: "env_dev"
+ alg:
+ type: string
+ description: The cryptographic algorithm used for signing.
+ enum:
+ - ES256
+ - PS256
+ - Ed25519
+ example: "ES256"
+ required:
+ - signer
+ - alg
asset_s3_uri:
type: string
+ format: uri
nullable: true
- description: An S3 URI for the signed asset. This field is populated if the resulting asset is larger than 3MB. If the asset is inlined in `asset_b64`, this will be null.
- example: "s3://Que-signed-assets/a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8/signed.jpg"
+ description: S3 URI of the signed asset. The signed asset is automatically uploaded to S3 with the embedded C2PA manifest.
+ pattern: "^s3://[^/]+/.+$"
+ example: "s3://que-signed-assets/uuid/signed.jpg"
required:
- assurance
- evidence
@@ -432,17 +530,17 @@ components:
# ----- /v1/assets/presign -----
PresignResponse:
type: object
- description: A presigned URL that can be used for a temporary, authenticated upload to S3.
+ description: A presigned URL and object key for secure S3 upload. Use the URL to upload your asset directly to S3, then use the returned key for signing/verification operations.
properties:
url:
type: string
format: uri
- description: The presigned S3 URL to which the client should PUT the asset file.
- example: "https://Que-customer-uploads.s3.amazonaws.com/new-asset-key?AWSAccessKeyId=..."
+ description: The presigned S3 URL for direct upload. Make a PUT request to this URL with your asset file as the body. The URL is valid for a limited time (typically 15 minutes).
+ example: "https://que-assets-dev.s3.us-east-2.amazonaws.com/uploads/user123/asset.jpg?AWSAccessKeyId=...&Signature=...&Expires=..."
key:
type: string
- description: The S3 object key that the asset will have after being uploaded. This key should be used in subsequent API calls.
- example: "uploads/user123/timestamp/asset.jpg"
+ description: The S3 object key where your asset will be stored. Use this key in subsequent sign/verify API calls to reference the uploaded asset.
+ example: "uploads/user123/asset.jpg"
required:
- url
- key
@@ -450,32 +548,45 @@ components:
# ----- /v1/trust-list -----
TrustListResponse:
type: object
- description: The C2PA trust list bundle, containing trusted certificate authorities and manufacturers.
+ description: The current C2PA trust list containing trusted certificate authorities, hardware manufacturers, and trust policies used for manifest verification.
properties:
version:
type: string
+ description: Version identifier for this trust list bundle.
example: "dev-1"
issued_at:
type: string
format: date-time
- example: "2025-08-15T20:00:00Z"
+ description: Timestamp when this trust list was issued.
+ example: "2024-01-15T10:00:00Z"
data:
type: object
+ description: The trust list data containing certificates and policies.
properties:
manufacturers:
type: array
+ description: List of trusted hardware manufacturers whose devices can create trusted provenance.
items:
type: string
+ example: "Canon Inc."
cas:
type: array
+ description: List of trusted Certificate Authority certificates in PEM format.
items:
type: string
- description: A trusted CA certificate in PEM format.
+ description: X.509 certificate in PEM format for a trusted Certificate Authority.
+ example: "-----BEGIN CERTIFICATE-----\nMIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF...\n-----END CERTIFICATE-----"
policy:
type: object
+ description: Trust policy configuration defining default trust behavior.
properties:
default:
type: string
+ enum:
+ - allow
+ - deny
+ description: Default trust policy when no specific rule applies.
+ example: "allow"
required:
- default
required:
@@ -487,13 +598,11 @@ components:
- issued_at
- data
example:
- version: "prod-2025-08-15"
- issued_at: "2025-08-15T20:00:00Z"
+ version: "dev-1"
+ issued_at: "2024-01-15T10:00:00Z"
data:
- manufacturers:
- - "Example Camera Corp"
- cas:
- - "-----BEGIN CERTIFICATE-----\nMIID...=\n-----END CERTIFICATE-----"
+ manufacturers: []
+ cas: []
policy:
default: "allow"
@@ -519,17 +628,39 @@ paths:
/v1/verify:
post:
summary: Verify the C2PA manifest of an asset
- description: Analyzes a digital asset (e.g., an image) to find, validate, and report on any embedded C2PA manifests. This allows you to confirm the asset's provenance and authenticity.
+ description: |
+ Analyzes a digital asset to find, validate, and report on any embedded C2PA manifests. This allows you to confirm the asset's provenance, authenticity, and processing history.
+
+ The asset is processed using memory-efficient streaming to temporary storage during verification. Returns detailed validation results including trust status, signer information, and any validation failures.
operationId: verifyAsset
security:
- ApiKeyAuth: []
requestBody:
- description: The asset to verify and the desired report detail level.
+ description: The asset to verify, report detail level, and optional verification parameters.
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/VerifyRequest"
+ examples:
+ basic-verification:
+ summary: Basic trust verification
+ value:
+ asset:
+ bucket: "que-assets-dev"
+ key: "uploads/photo.jpg"
+ mode: "summary"
+ detailed-verification:
+ summary: Detailed verification with remote manifests
+ value:
+ asset:
+ bucket: "que-assets-dev"
+ key: "uploads/document.pdf"
+ mode: "detailed"
+ allow_remote_manifests: true
+ include_certificates: true
+ limits:
+ max_asset_size_bytes: 52428800
responses:
'200':
description: Verification report successfully generated.
@@ -557,12 +688,23 @@ paths:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemResponse'
- example:
- type: "about:blank"
- title: "verification failed"
- status: 422
- code: "engine_verification"
- detail: "verification failed"
+ examples:
+ verification-failed:
+ summary: Verification failed
+ value:
+ type: "about:blank"
+ title: "verification failed"
+ status: 422
+ code: "engine_verification"
+ detail: "verification failed"
+ c2pa-error:
+ summary: C2PA processing error
+ value:
+ type: "about:blank"
+ title: "root operation failed"
+ status: 422
+ code: "engine_c2pa"
+ detail: "Unsupported manifest format"
'429':
$ref: '#/components/responses/RateLimited'
'500':
@@ -571,17 +713,40 @@ paths:
/v1/sign:
post:
summary: Sign an asset with a C2PA manifest
- description: Embeds a C2PA manifest into a digital asset and signs it using a server-side key. This cryptographically links the asset to its provenance information.
+ description: |
+ Embeds a C2PA manifest into a digital asset and signs it using a server-side cryptographic key. The asset is processed using memory-efficient streaming to temporary storage before signing.
+
+ This operation cryptographically links the asset to its provenance information, creating an immutable record of the asset's origin, authorship, and any processing history.
operationId: signAsset
security:
- ApiKeyAuth: []
requestBody:
- description: The asset to sign, the signing mode, and the C2PA manifest content.
+ description: The asset to sign, signing mode, manifest content, and optional processing limits.
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/SignRequest"
+ examples:
+ basic-signing:
+ summary: Basic asset signing with minimal manifest
+ value:
+ asset:
+ bucket: "que-assets-dev"
+ key: "uploads/photo.jpg"
+ mode: "server_measure"
+ manifest_json: "{\"title\":\"Original Photograph\",\"assertions\":[{\"label\":\"stds.schema-org.CreativeWork\",\"data\":{\"@context\":\"https://schema.org\",\"@type\":\"CreativeWork\",\"author\":[{\"@type\":\"Person\",\"name\":\"Jane Photographer\"}]}}]}"
+ advanced-signing:
+ summary: Advanced signing with custom actions and limits
+ value:
+ asset:
+ bucket: "que-assets-dev"
+ key: "uploads/document.pdf"
+ mode: "server_measure"
+ manifest_json: "{\"title\":\"Signed Document\",\"assertions\":[{\"label\":\"stds.schema-org.CreativeWork\",\"data\":{\"@context\":\"https://schema.org\",\"@type\":\"CreativeWork\",\"author\":[{\"@type\":\"Person\",\"name\":\"John Author\"}]}}]}"
+ limits:
+ max_asset_size_bytes: 104857600
+ stream_timeout_ms: 60000
responses:
'200':
description: The asset was successfully signed.
@@ -594,7 +759,6 @@ paths:
evidence:
signer: "env_dev"
alg: "ES256"
- asset_b64: null
asset_s3_uri: "s3://Que-signed-assets/uuid/signed.jpg"
'400':
description: Bad request due to invalid input.
@@ -613,7 +777,28 @@ paths:
'403':
$ref: '#/components/responses/Forbidden'
'422':
- $ref: '#/components/responses/UnprocessableEntity'
+ description: Signing failed due to asset processing error or invalid manifest.
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ProblemResponse'
+ examples:
+ c2pa-error:
+ summary: C2PA processing error
+ value:
+ type: "about:blank"
+ title: "root operation failed"
+ status: 422
+ code: "engine_c2pa"
+ detail: "Unsupported manifest format"
+ json-error:
+ summary: JSON parsing error
+ value:
+ type: "about:blank"
+ title: "json parsing failed"
+ status: 400
+ code: "engine_json"
+ detail: "invalid json"
'429':
$ref: '#/components/responses/RateLimited'
'500':
@@ -623,8 +808,17 @@ paths:
post:
tags:
- Asset Management
- summary: Get an S3 presigned URL for uploads
- description: Generates a temporary, secure URL that a client can use to upload a large asset directly to S3. This is the recommended workflow for assets larger than a few megabytes to avoid sending large payloads through the API server.
+ summary: Get an S3 presigned URL for secure uploads
+ description: |
+ Generates a temporary, cryptographically signed URL that allows secure direct upload of assets to S3 without exposing AWS credentials.
+
+ This is the recommended approach for uploading assets, especially large files, as it:
+ - Avoids sending large payloads through the API server
+ - Provides secure, time-limited access to S3
+ - Enables resumable uploads for better reliability
+ - Reduces API server memory usage and network overhead
+
+ Use the returned URL to make a PUT request with your asset file, then use the returned key for subsequent sign/verify operations.
operationId: getPresignedUrl
security:
- ApiKeyAuth: []
@@ -652,13 +846,21 @@ paths:
tags:
- Utility
summary: Retrieve the current C2PA trust bundle
- description: Fetches the latest C2PA trust list, which includes trusted certificate authorities and hardware manufacturers. This list is used by verifiers to determine if a signature on a manifest is from a trusted source.
+ description: |
+ Fetches the latest C2PA trust list containing trusted certificate authorities, hardware manufacturers, and trust policies.
+
+ The trust list is used during manifest verification to:
+ - Validate signer certificates against trusted Certificate Authorities
+ - Verify hardware manufacturer claims for camera-captured content
+ - Apply trust policies for different validation scenarios
+
+ Trust lists are versioned and should be refreshed periodically as new trusted entities are added or certificates expire.
operationId: getTrustList
security:
- ApiKeyAuth: []
responses:
'200':
- description: The current C2PA trust list.
+ description: The current trust list.
content:
application/json:
schema:
diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock
index 31aef42..b8c08b5 100644
--- a/.speakeasy/workflow.lock
+++ b/.speakeasy/workflow.lock
@@ -1,20 +1,21 @@
-speakeasyVersion: 1.606.3
+speakeasyVersion: 1.621.0
sources:
Que API:
sourceNamespace: que-api
- sourceRevisionDigest: sha256:8d011d455ba3d4da5196eda0e3d524ecfe52d75c3419f2f065cd90d81f1dc49f
- sourceBlobDigest: sha256:3c1e48a67c019faed5972f2105b937c1b026076b5927621db38e3967ce5a7385
+ sourceRevisionDigest: sha256:34954edfb908002665dacd33ccf10bcc5454c2b1b48d70c356dc7f059038cb08
+ sourceBlobDigest: sha256:53c4b50cdb8f9f86777d7b7787c2841a6de6c1b9141bbca7f42509fdb1e9526a
tags:
- latest
+ - speakeasy-sdk-regen-1758290879
- 1.0.0
targets:
que:
source: Que API
sourceNamespace: que-api
- sourceRevisionDigest: sha256:8d011d455ba3d4da5196eda0e3d524ecfe52d75c3419f2f065cd90d81f1dc49f
- sourceBlobDigest: sha256:3c1e48a67c019faed5972f2105b937c1b026076b5927621db38e3967ce5a7385
+ sourceRevisionDigest: sha256:34954edfb908002665dacd33ccf10bcc5454c2b1b48d70c356dc7f059038cb08
+ sourceBlobDigest: sha256:53c4b50cdb8f9f86777d7b7787c2841a6de6c1b9141bbca7f42509fdb1e9526a
codeSamplesNamespace: que-api-python-code-samples
- codeSamplesRevisionDigest: sha256:df79ab3d84facb1590b1bd6da94b3224467583fbf0c802359304b7a8788f38ae
+ codeSamplesRevisionDigest: sha256:e06089f7bf1a7798be279876f8af06ba3228e36ac454e548ff4c6e70746bf0dc
workflow:
workflowVersion: 1.0.0
speakeasyVersion: latest
@@ -29,6 +30,9 @@ workflow:
que:
target: python
source: Que API
+ publish:
+ pypi:
+ token: $pypi_token
codeSamples:
registry:
location: registry.speakeasyapi.dev/que-cr2/que/que-api-python-code-samples
diff --git a/README-PYPI.md b/README-PYPI.md
new file mode 100644
index 0000000..3bf078d
--- /dev/null
+++ b/README-PYPI.md
@@ -0,0 +1,607 @@
+# que_media
+
+Developer-friendly & type-safe Python SDK specifically catered to leverage *que_media* API.
+
+
+
+
+
+
+
+## Summary
+
+Que API: Welcome to the Que Public HTTP API for C2PA (Content Authenticity Initiative) provenance management.
+
+Our platform provides robust tools for working with digital asset provenance through C2PA manifests, enabling you to sign and verify digital assets to ensure their authenticity, origin, and processing history.
+
+**Key Features:**
+* **Memory-Efficient Streaming**: Assets are processed using streaming techniques to minimize memory usage, supporting large files efficiently
+* **Verify**: Inspect and validate C2PA manifests embedded in assets with multiple detail levels
+* **Sign**: Embed comprehensive C2PA manifests into your assets with server-side cryptographic signatures
+* **Trust Management**: Retrieve and validate against current trust lists containing trusted certificate authorities and manufacturers
+* **Secure Uploads**: Direct-to-S3 uploads via presigned URLs for large assets
+
+**Authentication:**
+All endpoints (except for `/healthz`) are secured and require an API key to be passed in the `x-api-key` header.
+
+**Processing Architecture:**
+Assets are streamed from S3 or URLs to temporary storage during processing to ensure O(chunk_size) memory usage instead of O(file_size), enabling efficient handling of large files on containerized platforms.
+
+Usage of this API is tracked via Firehose for billing and monitoring purposes.
+
+
+For more information about the API: [Find more detailed documentation and tutorials here.](https://docs.addque.org)
+
+
+
+## Table of Contents
+
+* [que_media](https://github.com/QuePlatform/PythonSDK/blob/master/#quemedia)
+ * [SDK Installation](https://github.com/QuePlatform/PythonSDK/blob/master/#sdk-installation)
+ * [IDE Support](https://github.com/QuePlatform/PythonSDK/blob/master/#ide-support)
+ * [SDK Example Usage](https://github.com/QuePlatform/PythonSDK/blob/master/#sdk-example-usage)
+ * [Authentication](https://github.com/QuePlatform/PythonSDK/blob/master/#authentication)
+ * [Available Resources and Operations](https://github.com/QuePlatform/PythonSDK/blob/master/#available-resources-and-operations)
+ * [Retries](https://github.com/QuePlatform/PythonSDK/blob/master/#retries)
+ * [Error Handling](https://github.com/QuePlatform/PythonSDK/blob/master/#error-handling)
+ * [Server Selection](https://github.com/QuePlatform/PythonSDK/blob/master/#server-selection)
+ * [Custom HTTP Client](https://github.com/QuePlatform/PythonSDK/blob/master/#custom-http-client)
+ * [Resource Management](https://github.com/QuePlatform/PythonSDK/blob/master/#resource-management)
+ * [Debugging](https://github.com/QuePlatform/PythonSDK/blob/master/#debugging)
+* [Development](https://github.com/QuePlatform/PythonSDK/blob/master/#development)
+ * [Maturity](https://github.com/QuePlatform/PythonSDK/blob/master/#maturity)
+ * [Contributions](https://github.com/QuePlatform/PythonSDK/blob/master/#contributions)
+
+
+
+
+## SDK Installation
+
+> [!NOTE]
+> **Python version upgrade policy**
+>
+> Once a Python version reaches its [official end of life date](https://devguide.python.org/versions/), a 3-month grace period is provided for users to upgrade. Following this grace period, the minimum python version supported in the SDK will be updated.
+
+The SDK can be installed with *uv*, *pip*, or *poetry* package managers.
+
+### uv
+
+*uv* is a fast Python package installer and resolver, designed as a drop-in replacement for pip and pip-tools. It's recommended for its speed and modern Python tooling capabilities.
+
+```bash
+uv add que_media
+```
+
+### PIP
+
+*PIP* is the default package installer for Python, enabling easy installation and management of packages from PyPI via the command line.
+
+```bash
+pip install que_media
+```
+
+### Poetry
+
+*Poetry* is a modern tool that simplifies dependency management and package publishing by using a single `pyproject.toml` file to handle project metadata and dependencies.
+
+```bash
+poetry add que_media
+```
+
+### 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 que_media 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 = [
+# "que_media",
+# ]
+# ///
+
+from que_media import Que
+
+sdk = Que(
+ # 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.
+
+
+
+## IDE Support
+
+### PyCharm
+
+Generally, the SDK will work well with most IDEs out of the box. However, when using PyCharm, you can enjoy much better integration with Pydantic by installing an additional plugin.
+
+- [PyCharm Pydantic Plugin](https://docs.pydantic.dev/latest/integrations/pycharm/)
+
+
+
+## SDK Example Usage
+
+### Example
+
+```python
+# Synchronous Example
+import os
+from que_media import Que
+
+
+with Que(
+ api_key_auth=os.getenv("QUE_API_KEY_AUTH", ""),
+) as que:
+
+ res = que.verify_asset(asset={
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
+
+ # Handle response
+ print(res)
+```
+
+
+
+The same SDK client can also be used to make asynchronous requests by importing asyncio.
+```python
+# Asynchronous Example
+import asyncio
+import os
+from que_media import Que
+
+async def main():
+
+ async with Que(
+ api_key_auth=os.getenv("QUE_API_KEY_AUTH", ""),
+ ) as que:
+
+ res = await que.verify_asset_async(asset={
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
+
+ # Handle response
+ print(res)
+
+asyncio.run(main())
+```
+
+
+
+## Authentication
+
+### Per-Client Security Schemes
+
+This SDK supports the following security scheme globally:
+
+| Name | Type | Scheme | Environment Variable |
+| -------------- | ------ | ------- | -------------------- |
+| `api_key_auth` | apiKey | API key | `QUE_API_KEY_AUTH` |
+
+To authenticate with the API the `api_key_auth` parameter must be set when initializing the SDK client instance. For example:
+```python
+import os
+from que_media import Que
+
+
+with Que(
+ api_key_auth=os.getenv("QUE_API_KEY_AUTH", ""),
+) as que:
+
+ res = que.verify_asset(asset={
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
+
+ # Handle response
+ print(res)
+
+```
+
+
+
+## Available Resources and Operations
+
+
+Available methods
+
+### [asset_management](https://github.com/QuePlatform/PythonSDK/blob/master/docs/sdks/assetmanagement/README.md)
+
+* [get_presigned_url](https://github.com/QuePlatform/PythonSDK/blob/master/docs/sdks/assetmanagement/README.md#get_presigned_url) - Get an S3 presigned URL for secure uploads
+
+### [Que SDK](https://github.com/QuePlatform/PythonSDK/blob/master/docs/sdks/que/README.md)
+
+* [verify_asset](https://github.com/QuePlatform/PythonSDK/blob/master/docs/sdks/que/README.md#verify_asset) - Verify the C2PA manifest of an asset
+* [sign_asset](https://github.com/QuePlatform/PythonSDK/blob/master/docs/sdks/que/README.md#sign_asset) - Sign an asset with a C2PA manifest
+
+### [utility](https://github.com/QuePlatform/PythonSDK/blob/master/docs/sdks/utility/README.md)
+
+* [get_health_check](https://github.com/QuePlatform/PythonSDK/blob/master/docs/sdks/utility/README.md#get_health_check) - Service Health Check
+* [get_trust_list](https://github.com/QuePlatform/PythonSDK/blob/master/docs/sdks/utility/README.md#get_trust_list) - Retrieve the current C2PA trust bundle
+
+
+
+
+
+## Retries
+
+Some of the endpoints in this SDK support retries. If you use the SDK without any configuration, it will fall back to the default retry strategy provided by the API. However, the default retry strategy can be overridden on a per-operation basis, or across the entire SDK.
+
+To change the default retry strategy for a single API call, simply provide a `RetryConfig` object to the call:
+```python
+import os
+from que_media import Que
+from que_media.utils import BackoffStrategy, RetryConfig
+
+
+with Que(
+ api_key_auth=os.getenv("QUE_API_KEY_AUTH", ""),
+) as que:
+
+ res = que.verify_asset(asset={
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ },
+ RetryConfig("backoff", BackoffStrategy(1, 50, 1.1, 100), False))
+
+ # Handle response
+ print(res)
+
+```
+
+If you'd like to override the default retry strategy for all operations that support retries, you can use the `retry_config` optional parameter when initializing the SDK:
+```python
+import os
+from que_media import Que
+from que_media.utils import BackoffStrategy, RetryConfig
+
+
+with Que(
+ retry_config=RetryConfig("backoff", BackoffStrategy(1, 50, 1.1, 100), False),
+ api_key_auth=os.getenv("QUE_API_KEY_AUTH", ""),
+) as que:
+
+ res = que.verify_asset(asset={
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
+
+ # Handle response
+ print(res)
+
+```
+
+
+
+## Error Handling
+
+[`QueError`](https://github.com/QuePlatform/PythonSDK/blob/master/./src/que_media/errors/queerror.py) is the base class for all HTTP error responses. It has the following properties:
+
+| 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](https://github.com/QuePlatform/PythonSDK/blob/master/#error-classes). |
+
+### Example
+```python
+import os
+from que_media import Que, errors
+
+
+with Que(
+ api_key_auth=os.getenv("QUE_API_KEY_AUTH", ""),
+) as que:
+ res = None
+ try:
+
+ res = que.verify_asset(asset={
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
+
+ # Handle response
+ print(res)
+
+
+ except errors.QueError 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.ProblemResponseError):
+ print(e.data.type) # str
+ print(e.data.title) # str
+ print(e.data.status) # int
+ print(e.data.code) # str
+ print(e.data.detail) # OptionalNullable[str]
+```
+
+### Error Classes
+**Primary errors:**
+* [`QueError`](https://github.com/QuePlatform/PythonSDK/blob/master/./src/que_media/errors/queerror.py): The base class for HTTP error responses.
+ * [`ProblemResponseError`](https://github.com/QuePlatform/PythonSDK/blob/master/./src/que_media/errors/problemresponseerror.py): An RFC 7807 problem details response. *
+
+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 [`QueError`](https://github.com/QuePlatform/PythonSDK/blob/master/./src/que_media/errors/queerror.py)**:
+* [`ResponseValidationError`](https://github.com/QuePlatform/PythonSDK/blob/master/./src/que_media/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.
+
+
+
+\* Check [the method documentation](https://github.com/QuePlatform/PythonSDK/blob/master/#available-resources-and-operations) to see if the error is applicable.
+
+
+
+## Server Selection
+
+### Server Variables
+
+The default server `https://{environment}.addque.org/` contains variables and is set to `https://dev-api.addque.org/` by default. To override default values, the following parameters are available when initializing the SDK client instance:
+
+| Variable | Parameter | Default | Description |
+| ------------- | ------------------ | ----------- | --------------------------- |
+| `environment` | `environment: str` | `"dev-api"` | The deployment environment. |
+
+#### Example
+
+```python
+import os
+from que_media import Que
+
+
+with Que(
+ environment=""
+ api_key_auth=os.getenv("QUE_API_KEY_AUTH", ""),
+) as que:
+
+ res = que.verify_asset(asset={
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
+
+ # Handle response
+ print(res)
+
+```
+
+### Override Server URL Per-Client
+
+The default server can be overridden globally by passing a URL to the `server_url: str` optional parameter when initializing the SDK client instance. For example:
+```python
+import os
+from que_media import Que
+
+
+with Que(
+ server_url="https://dev-api.addque.org/",
+ api_key_auth=os.getenv("QUE_API_KEY_AUTH", ""),
+) as que:
+
+ res = que.verify_asset(asset={
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
+
+ # Handle response
+ print(res)
+
+```
+
+
+
+## Custom HTTP Client
+
+The Python SDK makes API calls using the [httpx](https://www.python-httpx.org/) HTTP library. In order to provide a convenient way to configure timeouts, cookies, proxies, custom headers, and other low-level configuration, you can initialize the SDK client with your own HTTP client instance.
+Depending on whether you are using the sync or async version of the SDK, you can pass an instance of `HttpClient` or `AsyncHttpClient` respectively, which are Protocol's ensuring that the client has the necessary methods to make API calls.
+This allows you to wrap the client with your own custom logic, such as adding custom headers, logging, or error handling, or you can just pass an instance of `httpx.Client` or `httpx.AsyncClient` directly.
+
+For example, you could specify a header for every request that this sdk makes as follows:
+```python
+from que_media import Que
+import httpx
+
+http_client = httpx.Client(headers={"x-custom-header": "someValue"})
+s = Que(client=http_client)
+```
+
+or you could wrap the client with your own custom logic:
+```python
+from que_media import Que
+from que_media.httpclient import AsyncHttpClient
+import httpx
+
+class CustomClient(AsyncHttpClient):
+ client: AsyncHttpClient
+
+ def __init__(self, client: AsyncHttpClient):
+ self.client = client
+
+ async def send(
+ self,
+ request: httpx.Request,
+ *,
+ stream: bool = False,
+ auth: Union[
+ httpx._types.AuthTypes, httpx._client.UseClientDefault, None
+ ] = httpx.USE_CLIENT_DEFAULT,
+ follow_redirects: Union[
+ bool, httpx._client.UseClientDefault
+ ] = httpx.USE_CLIENT_DEFAULT,
+ ) -> httpx.Response:
+ request.headers["Client-Level-Header"] = "added by client"
+
+ return await self.client.send(
+ request, stream=stream, auth=auth, follow_redirects=follow_redirects
+ )
+
+ def build_request(
+ self,
+ method: str,
+ url: httpx._types.URLTypes,
+ *,
+ content: Optional[httpx._types.RequestContent] = None,
+ data: Optional[httpx._types.RequestData] = None,
+ files: Optional[httpx._types.RequestFiles] = None,
+ json: Optional[Any] = None,
+ params: Optional[httpx._types.QueryParamTypes] = None,
+ headers: Optional[httpx._types.HeaderTypes] = None,
+ cookies: Optional[httpx._types.CookieTypes] = None,
+ timeout: Union[
+ httpx._types.TimeoutTypes, httpx._client.UseClientDefault
+ ] = httpx.USE_CLIENT_DEFAULT,
+ extensions: Optional[httpx._types.RequestExtensions] = None,
+ ) -> httpx.Request:
+ return self.client.build_request(
+ method,
+ url,
+ content=content,
+ data=data,
+ files=files,
+ json=json,
+ params=params,
+ headers=headers,
+ cookies=cookies,
+ timeout=timeout,
+ extensions=extensions,
+ )
+
+s = Que(async_client=CustomClient(httpx.AsyncClient()))
+```
+
+
+
+## Resource Management
+
+The `Que` class implements the context manager protocol and registers a finalizer function to close the underlying sync and async HTTPX clients it uses under the hood. This will close HTTP connections, release memory and free up other resources held by the SDK. In short-lived Python programs and notebooks that make a few SDK method calls, resource management may not be a concern. However, in longer-lived programs, it is beneficial to create a single SDK instance via a [context manager][context-manager] and reuse it across the application.
+
+[context-manager]: https://docs.python.org/3/reference/datamodel.html#context-managers
+
+```python
+import os
+from que_media import Que
+def main():
+
+ with Que(
+ api_key_auth=os.getenv("QUE_API_KEY_AUTH", ""),
+ ) as que:
+ # Rest of application here...
+
+
+# Or when using async:
+async def amain():
+
+ async with Que(
+ api_key_auth=os.getenv("QUE_API_KEY_AUTH", ""),
+ ) as que:
+ # Rest of application here...
+```
+
+
+
+## Debugging
+
+You can setup your SDK to emit debug logs for SDK requests and responses.
+
+You can pass your own logger class directly into your SDK.
+```python
+from que_media import Que
+import logging
+
+logging.basicConfig(level=logging.DEBUG)
+s = Que(debug_logger=logging.getLogger("que_media"))
+```
+
+You can also enable a default debug logger by setting an environment variable `QUE_DEBUG` to true.
+
+
+
+
+# Development
+
+## Maturity
+
+This SDK is in beta, and there may be breaking changes between versions without a major version update. Therefore, we recommend pinning usage
+to a specific package version. This way, you can install the same version each time without breaking changes unless you are intentionally
+looking for the latest version.
+
+## Contributions
+
+While we value open-source contributions to this SDK, this library is generated programmatically. Any manual changes added to internal files will be overwritten on the next generation.
+We look forward to hearing your feedback. Feel free to open a PR or an issue with a proof of concept and we'll do our best to include it in a future release.
+
+### SDK Created by [Speakeasy](https://www.speakeasy.com/?utm_source=que-media&utm_campaign=python)
diff --git a/README.md b/README.md
index e83d481..3c609e0 100644
--- a/README.md
+++ b/README.md
@@ -15,16 +15,23 @@ Developer-friendly & type-safe Python SDK specifically catered to leverage *que_
## Summary
-Que API: Welcome to the Que Public HTTP API. Our platform provides robust tools for working with C2PA (Coalition for Content Provenance and Authenticity) manifests, enabling you to sign and verify digital assets to ensure their authenticity and provenance.
+Que API: Welcome to the Que Public HTTP API for C2PA (Content Authenticity Initiative) provenance management.
+
+Our platform provides robust tools for working with digital asset provenance through C2PA manifests, enabling you to sign and verify digital assets to ensure their authenticity, origin, and processing history.
**Key Features:**
-* **Verify**: Inspect and validate C2PA manifests embedded in assets.
-* **Sign**: Embed C2PA manifests into your assets with a server-side signature.
-* **Trust Management**: Retrieve the current C2PA trust list.
+* **Memory-Efficient Streaming**: Assets are processed using streaming techniques to minimize memory usage, supporting large files efficiently
+* **Verify**: Inspect and validate C2PA manifests embedded in assets with multiple detail levels
+* **Sign**: Embed comprehensive C2PA manifests into your assets with server-side cryptographic signatures
+* **Trust Management**: Retrieve and validate against current trust lists containing trusted certificate authorities and manufacturers
+* **Secure Uploads**: Direct-to-S3 uploads via presigned URLs for large assets
**Authentication:**
All endpoints (except for `/healthz`) are secured and require an API key to be passed in the `x-api-key` header.
+**Processing Architecture:**
+Assets are streamed from S3 or URLs to temporary storage during processing to ensure O(chunk_size) memory usage instead of O(file_size), enabling efficient handling of large files on containerized platforms.
+
Usage of this API is tracked via Firehose for billing and monitoring purposes.
@@ -55,10 +62,6 @@ For more information about the API: [Find more detailed documentation and tutori
## SDK Installation
-> [!TIP]
-> To finish publishing your SDK to PyPI you must [run your first generation action](https://www.speakeasy.com/docs/github-setup#step-by-step-guide).
-
-
> [!NOTE]
> **Python version upgrade policy**
>
@@ -71,7 +74,7 @@ The SDK can be installed with *uv*, *pip*, or *poetry* package managers.
*uv* is a fast Python package installer and resolver, designed as a drop-in replacement for pip and pip-tools. It's recommended for its speed and modern Python tooling capabilities.
```bash
-uv add git+.git
+uv add que_media
```
### PIP
@@ -79,7 +82,7 @@ uv add git+.git
*PIP* is the default package installer for Python, enabling easy installation and management of packages from PyPI via the command line.
```bash
-pip install git+.git
+pip install que_media
```
### Poetry
@@ -87,7 +90,7 @@ pip install git+.git
*Poetry* is a modern tool that simplifies dependency management and package publishing by using a single `pyproject.toml` file to handle project metadata and dependencies.
```bash
-poetry add git+.git
+poetry add que_media
```
### Shell and script usage with `uv`
@@ -140,7 +143,7 @@ Generally, the SDK will work well with most IDEs out of the box. However, when u
```python
# Synchronous Example
import os
-from que_media import Que, models
+from que_media import Que
with Que(
@@ -148,8 +151,14 @@ with Que(
) as que:
res = que.verify_asset(asset={
- "url": "https://example.com/images/provenance-image.jpg",
- }, mode=models.VerifyRequestMode.DETAILED)
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
# Handle response
print(res)
@@ -162,7 +171,7 @@ The same SDK client can also be used to make asynchronous requests by importing
# Asynchronous Example
import asyncio
import os
-from que_media import Que, models
+from que_media import Que
async def main():
@@ -171,8 +180,14 @@ async def main():
) as que:
res = await que.verify_asset_async(asset={
- "url": "https://example.com/images/provenance-image.jpg",
- }, mode=models.VerifyRequestMode.DETAILED)
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
# Handle response
print(res)
@@ -195,7 +210,7 @@ This SDK supports the following security scheme globally:
To authenticate with the API the `api_key_auth` parameter must be set when initializing the SDK client instance. For example:
```python
import os
-from que_media import Que, models
+from que_media import Que
with Que(
@@ -203,8 +218,14 @@ with Que(
) as que:
res = que.verify_asset(asset={
- "url": "https://example.com/images/provenance-image.jpg",
- }, mode=models.VerifyRequestMode.DETAILED)
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
# Handle response
print(res)
@@ -220,7 +241,7 @@ with Que(
### [asset_management](docs/sdks/assetmanagement/README.md)
-* [get_presigned_url](docs/sdks/assetmanagement/README.md#get_presigned_url) - Get an S3 presigned URL for uploads
+* [get_presigned_url](docs/sdks/assetmanagement/README.md#get_presigned_url) - Get an S3 presigned URL for secure uploads
### [Que SDK](docs/sdks/que/README.md)
@@ -243,7 +264,7 @@ Some of the endpoints in this SDK support retries. If you use the SDK without an
To change the default retry strategy for a single API call, simply provide a `RetryConfig` object to the call:
```python
import os
-from que_media import Que, models
+from que_media import Que
from que_media.utils import BackoffStrategy, RetryConfig
@@ -252,8 +273,14 @@ with Que(
) as que:
res = que.verify_asset(asset={
- "url": "https://example.com/images/provenance-image.jpg",
- }, mode=models.VerifyRequestMode.DETAILED,
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ },
RetryConfig("backoff", BackoffStrategy(1, 50, 1.1, 100), False))
# Handle response
@@ -264,7 +291,7 @@ with Que(
If you'd like to override the default retry strategy for all operations that support retries, you can use the `retry_config` optional parameter when initializing the SDK:
```python
import os
-from que_media import Que, models
+from que_media import Que
from que_media.utils import BackoffStrategy, RetryConfig
@@ -274,8 +301,14 @@ with Que(
) as que:
res = que.verify_asset(asset={
- "url": "https://example.com/images/provenance-image.jpg",
- }, mode=models.VerifyRequestMode.DETAILED)
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
# Handle response
print(res)
@@ -300,7 +333,7 @@ with Que(
### Example
```python
import os
-from que_media import Que, errors, models
+from que_media import Que, errors
with Que(
@@ -310,8 +343,14 @@ with Que(
try:
res = que.verify_asset(asset={
- "url": "https://example.com/images/provenance-image.jpg",
- }, mode=models.VerifyRequestMode.DETAILED)
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
# Handle response
print(res)
@@ -372,7 +411,7 @@ The default server `https://{environment}.addque.org/` contains variables and is
```python
import os
-from que_media import Que, models
+from que_media import Que
with Que(
@@ -381,8 +420,14 @@ with Que(
) as que:
res = que.verify_asset(asset={
- "url": "https://example.com/images/provenance-image.jpg",
- }, mode=models.VerifyRequestMode.DETAILED)
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
# Handle response
print(res)
@@ -394,7 +439,7 @@ with Que(
The default server can be overridden globally by passing a URL to the `server_url: str` optional parameter when initializing the SDK client instance. For example:
```python
import os
-from que_media import Que, models
+from que_media import Que
with Que(
@@ -403,8 +448,14 @@ with Que(
) as que:
res = que.verify_asset(asset={
- "url": "https://example.com/images/provenance-image.jpg",
- }, mode=models.VerifyRequestMode.DETAILED)
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
# Handle response
print(res)
diff --git a/RELEASES.md b/RELEASES.md
new file mode 100644
index 0000000..310727d
--- /dev/null
+++ b/RELEASES.md
@@ -0,0 +1,11 @@
+
+
+## 2025-09-19 14:07:42
+### Changes
+Based on:
+- OpenAPI Doc
+- Speakeasy CLI 1.621.0 (2.707.0) https://github.com/speakeasy-api/speakeasy
+### Generated
+- [python v0.1.0] .
+### Releases
+- [PyPI v0.1.0] https://pypi.org/project/que_media/0.1.0 - .
\ No newline at end of file
diff --git a/USAGE.md b/USAGE.md
index 119b28b..6bcd892 100644
--- a/USAGE.md
+++ b/USAGE.md
@@ -2,7 +2,7 @@
```python
# Synchronous Example
import os
-from que_media import Que, models
+from que_media import Que
with Que(
@@ -10,8 +10,14 @@ with Que(
) as que:
res = que.verify_asset(asset={
- "url": "https://example.com/images/provenance-image.jpg",
- }, mode=models.VerifyRequestMode.DETAILED)
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
# Handle response
print(res)
@@ -24,7 +30,7 @@ The same SDK client can also be used to make asynchronous requests by importing
# Asynchronous Example
import asyncio
import os
-from que_media import Que, models
+from que_media import Que
async def main():
@@ -33,8 +39,14 @@ async def main():
) as que:
res = await que.verify_asset_async(asset={
- "url": "https://example.com/images/provenance-image.jpg",
- }, mode=models.VerifyRequestMode.DETAILED)
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
# Handle response
print(res)
diff --git a/docs/models/alg.md b/docs/models/alg.md
new file mode 100644
index 0000000..cd0b7e7
--- /dev/null
+++ b/docs/models/alg.md
@@ -0,0 +1,12 @@
+# Alg
+
+The cryptographic algorithm used for signing.
+
+
+## Values
+
+| Name | Value |
+| --------- | --------- |
+| `ES256` | ES256 |
+| `PS256` | PS256 |
+| `ED25519` | Ed25519 |
\ No newline at end of file
diff --git a/docs/models/assetrefdto.md b/docs/models/assetrefdto.md
index 510bb70..42d2857 100644
--- a/docs/models/assetrefdto.md
+++ b/docs/models/assetrefdto.md
@@ -1,14 +1,14 @@
# AssetRefDto
-A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object.
+A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage.
## Supported Types
-### `models.BytesBase64`
+### `models.S3`
```python
-value: models.BytesBase64 = /* values here */
+value: models.S3 = /* values here */
```
### `models.PresignedURL`
@@ -17,9 +17,3 @@ value: models.BytesBase64 = /* values here */
value: models.PresignedURL = /* values here */
```
-### `models.S3`
-
-```python
-value: models.S3 = /* values here */
-```
-
diff --git a/docs/models/assurance.md b/docs/models/assurance.md
new file mode 100644
index 0000000..1858be4
--- /dev/null
+++ b/docs/models/assurance.md
@@ -0,0 +1,11 @@
+# Assurance
+
+The level of assurance provided by the signing process.
+
+
+## Values
+
+| Name | Value |
+| ----------------- | ----------------- |
+| `SERVER_MEASURED` | server_measured |
+| `CLIENT_HASH` | client_hash |
\ No newline at end of file
diff --git a/docs/models/bytesbase64.md b/docs/models/bytesbase64.md
deleted file mode 100644
index 9f729bc..0000000
--- a/docs/models/bytesbase64.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# BytesBase64
-
-An asset provided as a Base64-encoded string. Suitable for small files.
-
-
-## Fields
-
-| Field | Type | Required | Description | Example |
-| -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
-| `b64` | *str* | :heavy_check_mark: | The raw bytes of the asset, encoded in Base64. | iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII= |
\ No newline at end of file
diff --git a/docs/models/cawgidentitydto.md b/docs/models/cawgidentitydto.md
new file mode 100644
index 0000000..10e1a84
--- /dev/null
+++ b/docs/models/cawgidentitydto.md
@@ -0,0 +1,13 @@
+# CawgIdentityDto
+
+Configuration to add a CAWG identity assertion during signing. Presence of this object enables CAWG.
+
+
+## Fields
+
+| Field | Type | Required | Description |
+| -------------------------------------------------------------- | -------------------------------------------------------------- | -------------------------------------------------------------- | -------------------------------------------------------------- |
+| `signer` | [Optional[models.Signer]](../models/signer.md) | :heavy_minus_sign: | N/A |
+| `signing_alg` | [Optional[models.SigningAlg]](../models/signingalg.md) | :heavy_minus_sign: | Algorithm used for the CAWG identity signature. |
+| `referenced_assertions` | List[*str*] | :heavy_minus_sign: | Assertion labels that the identity assertion should reference. |
+| `timestamper` | *Optional[str]* | :heavy_minus_sign: | Timestamper to use ("digicert" or "custom:"). |
\ No newline at end of file
diff --git a/docs/models/cawgverifydto.md b/docs/models/cawgverifydto.md
new file mode 100644
index 0000000..e567aa3
--- /dev/null
+++ b/docs/models/cawgverifydto.md
@@ -0,0 +1,11 @@
+# CawgVerifyDto
+
+Options controlling CAWG identity validation behavior during verification.
+
+
+## Fields
+
+| Field | Type | Required | Description |
+| ----------------------------------------------------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------- |
+| `validate_` | *Optional[bool]* | :heavy_minus_sign: | Whether to run CAWG identity validation. |
+| `require_valid_identity` | *Optional[bool]* | :heavy_minus_sign: | Whether to fail verification if CAWG identity is missing/invalid. |
\ No newline at end of file
diff --git a/docs/models/data.md b/docs/models/data.md
index 7016d45..ba5ef42 100644
--- a/docs/models/data.md
+++ b/docs/models/data.md
@@ -1,10 +1,12 @@
# Data
+The trust list data containing certificates and policies.
+
## Fields
-| Field | Type | Required | Description |
-| ------------------------------------ | ------------------------------------ | ------------------------------------ | ------------------------------------ |
-| `manufacturers` | List[*str*] | :heavy_check_mark: | N/A |
-| `cas` | List[*str*] | :heavy_check_mark: | N/A |
-| `policy` | [models.Policy](../models/policy.md) | :heavy_check_mark: | N/A |
\ No newline at end of file
+| Field | Type | Required | Description |
+| ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
+| `manufacturers` | List[*str*] | :heavy_check_mark: | List of trusted hardware manufacturers whose devices can create trusted provenance. |
+| `cas` | List[*str*] | :heavy_check_mark: | List of trusted Certificate Authority certificates in PEM format. |
+| `policy` | [models.Policy](../models/policy.md) | :heavy_check_mark: | Trust policy configuration defining default trust behavior. |
\ No newline at end of file
diff --git a/docs/models/default.md b/docs/models/default.md
new file mode 100644
index 0000000..2ef2b68
--- /dev/null
+++ b/docs/models/default.md
@@ -0,0 +1,11 @@
+# Default
+
+Default trust policy when no specific rule applies.
+
+
+## Values
+
+| Name | Value |
+| ------- | ------- |
+| `ALLOW` | allow |
+| `DENY` | deny |
\ No newline at end of file
diff --git a/docs/models/evidence.md b/docs/models/evidence.md
index 1e428b4..d64f1f6 100644
--- a/docs/models/evidence.md
+++ b/docs/models/evidence.md
@@ -1,9 +1,11 @@
# Evidence
-Metadata about the signature that was applied.
+Cryptographic evidence about the signature that was applied.
## Fields
-| Field | Type | Required | Description |
-| ----------- | ----------- | ----------- | ----------- |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| --------------------------------------------- | --------------------------------------------- | --------------------------------------------- | --------------------------------------------- | --------------------------------------------- |
+| `signer` | *str* | :heavy_check_mark: | Identifier for the signing entity/key used. | env_dev |
+| `alg` | [models.Alg](../models/alg.md) | :heavy_check_mark: | The cryptographic algorithm used for signing. | ES256 |
\ No newline at end of file
diff --git a/docs/models/gettrustlistresponse.md b/docs/models/gettrustlistresponse.md
index d417d04..e3845c3 100644
--- a/docs/models/gettrustlistresponse.md
+++ b/docs/models/gettrustlistresponse.md
@@ -3,7 +3,7 @@
## Fields
-| Field | Type | Required | Description | Example |
-| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `headers` | Dict[str, List[*str*]] | :heavy_check_mark: | N/A | |
-| `result` | [models.TrustListResponse](../models/trustlistresponse.md) | :heavy_check_mark: | N/A | {
"version": "prod-2025-08-15",
"issued_at": "2025-08-15T20:00:00Z",
"data": {
"manufacturers": [
"Example Camera Corp"
],
"cas": [
"-----BEGIN CERTIFICATE-----\nMIID...=\n-----END CERTIFICATE-----"
],
"policy": {
"default": "allow"
}
}
} |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
+| `headers` | Dict[str, List[*str*]] | :heavy_check_mark: | N/A | |
+| `result` | [models.TrustListResponse](../models/trustlistresponse.md) | :heavy_check_mark: | N/A | {
"version": "dev-1",
"issued_at": "2024-01-15T10:00:00Z",
"data": {
"manufacturers": [],
"cas": [],
"policy": {
"default": "allow"
}
}
} |
\ No newline at end of file
diff --git a/docs/models/limitsdto.md b/docs/models/limitsdto.md
new file mode 100644
index 0000000..25b3d32
--- /dev/null
+++ b/docs/models/limitsdto.md
@@ -0,0 +1,13 @@
+# LimitsDto
+
+Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling.
+
+
+## Fields
+
+| Field | Type | Required | Description | Example |
+| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `max_asset_size_bytes` | *Optional[int]* | :heavy_minus_sign: | Maximum allowed size for the asset file in bytes. This limit is enforced during the streaming download phase to prevent memory exhaustion. | 104857600 |
+| `max_output_size_bytes` | *Optional[int]* | :heavy_minus_sign: | Maximum allowed size for the output (signed asset) in bytes. This prevents excessive storage usage for signed assets. | 104857600 |
+| `max_stream_copy_bytes` | *Optional[int]* | :heavy_minus_sign: | Maximum allowed bytes for stream copying operations during processing. This limits the amount of data that can be buffered in memory during the signing/verification process. | 104857600 |
+| `stream_timeout_ms` | *Optional[int]* | :heavy_minus_sign: | Timeout for streaming operations in milliseconds. This prevents hanging operations when downloading from slow sources. | 30000 |
\ No newline at end of file
diff --git a/docs/models/manifestjson.md b/docs/models/manifestjson.md
deleted file mode 100644
index 41b9006..0000000
--- a/docs/models/manifestjson.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# ManifestJSON
-
-The C2PA manifest to embed in the asset. This is required when `mode` is `server_measure`.
-
-
-## Fields
-
-| Field | Type | Required | Description |
-| ----------- | ----------- | ----------- | ----------- |
\ No newline at end of file
diff --git a/docs/models/mode.md b/docs/models/mode.md
new file mode 100644
index 0000000..12b95f8
--- /dev/null
+++ b/docs/models/mode.md
@@ -0,0 +1,14 @@
+# Mode
+
+The signing mode to use.
+* `server_measure`: The server streams the asset, calculates its hash, and embeds the manifest. Requires `manifest_json`. This is the primary signing mode.
+* `client_hash`: The client provides the asset hash directly for offline signing. (Not yet implemented).
+
+
+
+## Values
+
+| Name | Value |
+| ---------------- | ---------------- |
+| `SERVER_MEASURE` | server_measure |
+| `CLIENT_HASH` | client_hash |
\ No newline at end of file
diff --git a/docs/models/policy.md b/docs/models/policy.md
index ebee51d..54c013f 100644
--- a/docs/models/policy.md
+++ b/docs/models/policy.md
@@ -1,8 +1,10 @@
# Policy
+Trust policy configuration defining default trust behavior.
+
## Fields
-| Field | Type | Required | Description |
-| ------------------ | ------------------ | ------------------ | ------------------ |
-| `default` | *str* | :heavy_check_mark: | N/A |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| --------------------------------------------------- | --------------------------------------------------- | --------------------------------------------------- | --------------------------------------------------- | --------------------------------------------------- |
+| `default` | [models.Default](../models/default.md) | :heavy_check_mark: | Default trust policy when no specific rule applies. | allow |
\ No newline at end of file
diff --git a/docs/models/presignedurl.md b/docs/models/presignedurl.md
index d905b7f..e659296 100644
--- a/docs/models/presignedurl.md
+++ b/docs/models/presignedurl.md
@@ -1,10 +1,10 @@
# PresignedURL
-An asset located at a publicly accessible or presigned URL.
+An asset accessible via HTTP/HTTPS URL. The URL must be enabled via the ALLOW_URL_ASSETS environment variable. The service will stream the file to temporary storage during processing.
## Fields
-| Field | Type | Required | Description | Example |
-| ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
-| `url` | *str* | :heavy_check_mark: | The URL where the asset can be downloaded. | https://my-public-bucket.s3.amazonaws.com/assets/image.jpg?AWSAccessKeyId=... |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| ------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------- |
+| `url` | *str* | :heavy_check_mark: | The HTTP/HTTPS URL of the asset. Must be publicly accessible. | https://example.com/assets/photo.jpg |
\ No newline at end of file
diff --git a/docs/models/presignresponse.md b/docs/models/presignresponse.md
index b22ff17..8891cd7 100644
--- a/docs/models/presignresponse.md
+++ b/docs/models/presignresponse.md
@@ -1,11 +1,11 @@
# PresignResponse
-A presigned URL that can be used for a temporary, authenticated upload to S3.
+A presigned URL and object key for secure S3 upload. Use the URL to upload your asset directly to S3, then use the returned key for signing/verification operations.
## Fields
-| Field | Type | Required | Description | Example |
-| ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
-| `url` | *str* | :heavy_check_mark: | The presigned S3 URL to which the client should PUT the asset file. | https://Que-customer-uploads.s3.amazonaws.com/new-asset-key?AWSAccessKeyId=... |
-| `key` | *str* | :heavy_check_mark: | The S3 object key that the asset will have after being uploaded. This key should be used in subsequent API calls. | uploads/user123/timestamp/asset.jpg |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `url` | *str* | :heavy_check_mark: | The presigned S3 URL for direct upload. Make a PUT request to this URL with your asset file as the body. The URL is valid for a limited time (typically 15 minutes). | https://que-assets-dev.s3.us-east-2.amazonaws.com/uploads/user123/asset.jpg?AWSAccessKeyId=...&Signature=...&Expires=... |
+| `key` | *str* | :heavy_check_mark: | The S3 object key where your asset will be stored. Use this key in subsequent sign/verify API calls to reference the uploaded asset. | uploads/user123/asset.jpg |
\ No newline at end of file
diff --git a/docs/models/s3.md b/docs/models/s3.md
index 0cfeff5..cfa1102 100644
--- a/docs/models/s3.md
+++ b/docs/models/s3.md
@@ -1,11 +1,11 @@
# S3
-An asset located in an S3 bucket that the Que service has access to.
+An asset located in an S3 bucket that the Que service has access to. The service will stream the file from S3 to temporary storage during processing.
## Fields
| Field | Type | Required | Description | Example |
| ------------------------------------------- | ------------------------------------------- | ------------------------------------------- | ------------------------------------------- | ------------------------------------------- |
-| `bucket` | *str* | :heavy_check_mark: | The name of the S3 bucket. | Que-customer-assets |
-| `key` | *str* | :heavy_check_mark: | The object key (path) within the S3 bucket. | uploads/user123/original.png |
\ No newline at end of file
+| `bucket` | *str* | :heavy_check_mark: | The name of the S3 bucket. | que-assets-dev |
+| `key` | *str* | :heavy_check_mark: | The object key (path) within the S3 bucket. | uploads/user123/asset.jpg |
\ No newline at end of file
diff --git a/docs/models/signer.md b/docs/models/signer.md
new file mode 100644
index 0000000..ef763a3
--- /dev/null
+++ b/docs/models/signer.md
@@ -0,0 +1,17 @@
+# Signer
+
+
+## Supported Types
+
+### `models.SignerUseMainSigner`
+
+```python
+value: models.SignerUseMainSigner = /* values here */
+```
+
+### `models.SignerSeparate`
+
+```python
+value: models.SignerSeparate = /* values here */
+```
+
diff --git a/docs/models/signerrefdto.md b/docs/models/signerrefdto.md
new file mode 100644
index 0000000..e3bf745
--- /dev/null
+++ b/docs/models/signerrefdto.md
@@ -0,0 +1,19 @@
+# SignerRefDto
+
+Reference to credentials for signing.
+
+
+## Supported Types
+
+### `models.SignerRefDtoEnv`
+
+```python
+value: models.SignerRefDtoEnv = /* values here */
+```
+
+### `models.SignerRefDtoLocal`
+
+```python
+value: models.SignerRefDtoLocal = /* values here */
+```
+
diff --git a/docs/models/signerrefdtoenv.md b/docs/models/signerrefdtoenv.md
new file mode 100644
index 0000000..b30a0dd
--- /dev/null
+++ b/docs/models/signerrefdtoenv.md
@@ -0,0 +1,10 @@
+# SignerRefDtoEnv
+
+
+## Fields
+
+| Field | Type | Required | Description |
+| -------------------------------------- | -------------------------------------- | -------------------------------------- | -------------------------------------- |
+| `type` | [models.TypeEnv](../models/typeenv.md) | :heavy_check_mark: | N/A |
+| `cert_var` | *str* | :heavy_check_mark: | N/A |
+| `key_var` | *str* | :heavy_check_mark: | N/A |
\ No newline at end of file
diff --git a/docs/models/signerrefdtolocal.md b/docs/models/signerrefdtolocal.md
new file mode 100644
index 0000000..59b4ed3
--- /dev/null
+++ b/docs/models/signerrefdtolocal.md
@@ -0,0 +1,10 @@
+# SignerRefDtoLocal
+
+
+## Fields
+
+| Field | Type | Required | Description |
+| ------------------------------------------ | ------------------------------------------ | ------------------------------------------ | ------------------------------------------ |
+| `type` | [models.TypeLocal](../models/typelocal.md) | :heavy_check_mark: | N/A |
+| `cert_path` | *str* | :heavy_check_mark: | N/A |
+| `key_path` | *str* | :heavy_check_mark: | N/A |
\ No newline at end of file
diff --git a/docs/models/signerseparate.md b/docs/models/signerseparate.md
new file mode 100644
index 0000000..ad2c6fb
--- /dev/null
+++ b/docs/models/signerseparate.md
@@ -0,0 +1,9 @@
+# SignerSeparate
+
+
+## Fields
+
+| Field | Type | Required | Description |
+| ------------------------------------------------ | ------------------------------------------------ | ------------------------------------------------ | ------------------------------------------------ |
+| `type` | [models.TypeSeparate](../models/typeseparate.md) | :heavy_check_mark: | N/A |
+| `signer` | [models.SignerRefDto](../models/signerrefdto.md) | :heavy_check_mark: | Reference to credentials for signing. |
\ No newline at end of file
diff --git a/docs/models/signerusemainsigner.md b/docs/models/signerusemainsigner.md
new file mode 100644
index 0000000..c07a37f
--- /dev/null
+++ b/docs/models/signerusemainsigner.md
@@ -0,0 +1,8 @@
+# SignerUseMainSigner
+
+
+## Fields
+
+| Field | Type | Required | Description |
+| ---------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------- |
+| `type` | [models.TypeUseMainSigner](../models/typeusemainsigner.md) | :heavy_check_mark: | N/A |
\ No newline at end of file
diff --git a/docs/models/signingalg.md b/docs/models/signingalg.md
new file mode 100644
index 0000000..2f30a16
--- /dev/null
+++ b/docs/models/signingalg.md
@@ -0,0 +1,13 @@
+# SigningAlg
+
+Algorithm used for the CAWG identity signature.
+
+
+## Values
+
+| Name | Value |
+| --------- | --------- |
+| `ED25519` | ed25519 |
+| `ES256` | es256 |
+| `ES384` | es384 |
+| `PS256` | ps256 |
\ No newline at end of file
diff --git a/docs/models/signrequest.md b/docs/models/signrequest.md
index 014d511..9b2ed06 100644
--- a/docs/models/signrequest.md
+++ b/docs/models/signrequest.md
@@ -1,10 +1,15 @@
# SignRequest
+Request to sign a digital asset with a C2PA manifest. The asset is processed using memory-efficient streaming to temporary storage.
+
## Fields
-| Field | Type | Required | Description |
-| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `asset` | [models.AssetRefDto](../models/assetrefdto.md) | :heavy_check_mark: | A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object. |
-| ~~`mode`~~ | [models.SignRequestMode](../models/signrequestmode.md) | :heavy_check_mark: | : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.
The signing mode to use.
* `server_measure`: The server will download the asset, calculate its hash, and embed the manifest. Requires `manifest_json`.
* `client_hash`: The client provides the asset hash directly. (Not yet implemented).
|
-| `manifest_json` | [Optional[models.ManifestJSON]](../models/manifestjson.md) | :heavy_minus_sign: | The C2PA manifest to embed in the asset. This is required when `mode` is `server_measure`. |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `asset` | [models.AssetRefDto](../models/assetrefdto.md) | :heavy_check_mark: | A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage. | |
+| `mode` | [models.Mode](../models/mode.md) | :heavy_check_mark: | The signing mode to use.
* `server_measure`: The server streams the asset, calculates its hash, and embeds the manifest. Requires `manifest_json`. This is the primary signing mode.
* `client_hash`: The client provides the asset hash directly for offline signing. (Not yet implemented).
| server_measure |
+| `manifest_json` | *Optional[str]* | :heavy_minus_sign: | JSON string containing the manifest to embed in the asset as a C2PA claim. This defines the provenance information and assertions about the asset. Required when `mode` is `server_measure`. | {"title":"Original Photograph","format":"image/jpeg","assertions":[{"label":"stds.schema-org.CreativeWork","data":{"@context":"https://schema.org","@type":"CreativeWork","author":[{"@type":"Person","name":"Jane Photographer"}]}}]} |
+| `cawg` | [Optional[models.CawgIdentityDto]](../models/cawgidentitydto.md) | :heavy_minus_sign: | Configuration to add a CAWG identity assertion during signing. Presence of this object enables CAWG. | |
+| `allow_insecure_remote_http` | *Optional[bool]* | :heavy_minus_sign: | Whether to allow HTTP (non-HTTPS) URLs for remote manifest resources. Disabled by default for security. | false |
+| `limits` | [Optional[models.LimitsDto]](../models/limitsdto.md) | :heavy_minus_sign: | Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling. | |
\ No newline at end of file
diff --git a/docs/models/signrequestmode.md b/docs/models/signrequestmode.md
deleted file mode 100644
index 34ac796..0000000
--- a/docs/models/signrequestmode.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# ~~SignRequestMode~~
-
-The signing mode to use.
-* `server_measure`: The server will download the asset, calculate its hash, and embed the manifest. Requires `manifest_json`.
-* `client_hash`: The client provides the asset hash directly. (Not yet implemented).
-
-
-> :warning: **DEPRECATED**: This will be removed in a future release, please migrate away from it as soon as possible.
-
-
-## Values
-
-| Name | Value |
-| ---------------- | ---------------- |
-| `SERVER_MEASURE` | server_measure |
-| `CLIENT_HASH` | client_hash |
\ No newline at end of file
diff --git a/docs/models/signresponse.md b/docs/models/signresponse.md
index aec30f8..f3e7314 100644
--- a/docs/models/signresponse.md
+++ b/docs/models/signresponse.md
@@ -1,13 +1,12 @@
# SignResponse
-The result of a successful signing operation, including the signed asset.
+The result of a successful signing operation. The signed asset is stored in S3 and the manifest is cryptographically embedded.
## Fields
-| Field | Type | Required | Description | Example |
-| ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `assurance` | *str* | :heavy_check_mark: | The level of assurance provided by the signing process. | server_measured |
-| `evidence` | [models.Evidence](../models/evidence.md) | :heavy_check_mark: | Metadata about the signature that was applied. | {
"signer": "env_dev",
"alg": "ES256"
} |
-| `asset_b64` | *OptionalNullable[str]* | :heavy_minus_sign: | The Base64-encoded signed asset. This field is populated if the resulting asset is 3MB or less. If larger, this will be null. | |
-| `asset_s3_uri` | *OptionalNullable[str]* | :heavy_minus_sign: | An S3 URI for the signed asset. This field is populated if the resulting asset is larger than 3MB. If the asset is inlined in `asset_b64`, this will be null. | s3://Que-signed-assets/a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8/signed.jpg |
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
+| `assurance` | [models.Assurance](../models/assurance.md) | :heavy_check_mark: | The level of assurance provided by the signing process. | server_measured |
+| `evidence` | [models.Evidence](../models/evidence.md) | :heavy_check_mark: | Cryptographic evidence about the signature that was applied. | |
+| `asset_s3_uri` | *OptionalNullable[str]* | :heavy_minus_sign: | S3 URI of the signed asset. The signed asset is automatically uploaded to S3 with the embedded C2PA manifest. | s3://que-signed-assets/uuid/signed.jpg |
\ No newline at end of file
diff --git a/docs/models/summary.md b/docs/models/summary.md
deleted file mode 100644
index 990d0e2..0000000
--- a/docs/models/summary.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Summary
-
-
-## Fields
-
-| Field | Type | Required | Description |
-| ------------------ | ------------------ | ------------------ | ------------------ |
-| `is_trusted` | *Optional[bool]* | :heavy_minus_sign: | N/A |
-| `signer` | *Optional[str]* | :heavy_minus_sign: | N/A |
\ No newline at end of file
diff --git a/docs/models/trustlistresponse.md b/docs/models/trustlistresponse.md
index d7b52a3..d3231ae 100644
--- a/docs/models/trustlistresponse.md
+++ b/docs/models/trustlistresponse.md
@@ -1,12 +1,12 @@
# TrustListResponse
-The C2PA trust list bundle, containing trusted certificate authorities and manufacturers.
+The current C2PA trust list containing trusted certificate authorities, hardware manufacturers, and trust policies used for manifest verification.
## Fields
| Field | Type | Required | Description | Example |
| -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------- |
-| `version` | *str* | :heavy_check_mark: | N/A | dev-1 |
-| `issued_at` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_check_mark: | N/A | 2025-08-15T20:00:00Z |
-| `data` | [models.Data](../models/data.md) | :heavy_check_mark: | N/A | |
\ No newline at end of file
+| `version` | *str* | :heavy_check_mark: | Version identifier for this trust list bundle. | dev-1 |
+| `issued_at` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_check_mark: | Timestamp when this trust list was issued. | 2024-01-15T10:00:00Z |
+| `data` | [models.Data](../models/data.md) | :heavy_check_mark: | The trust list data containing certificates and policies. | |
\ No newline at end of file
diff --git a/docs/models/typeenv.md b/docs/models/typeenv.md
new file mode 100644
index 0000000..0a1a4f5
--- /dev/null
+++ b/docs/models/typeenv.md
@@ -0,0 +1,8 @@
+# TypeEnv
+
+
+## Values
+
+| Name | Value |
+| ----- | ----- |
+| `ENV` | env |
\ No newline at end of file
diff --git a/docs/models/typelocal.md b/docs/models/typelocal.md
new file mode 100644
index 0000000..a00d7e6
--- /dev/null
+++ b/docs/models/typelocal.md
@@ -0,0 +1,8 @@
+# TypeLocal
+
+
+## Values
+
+| Name | Value |
+| ------- | ------- |
+| `LOCAL` | local |
\ No newline at end of file
diff --git a/docs/models/typeseparate.md b/docs/models/typeseparate.md
new file mode 100644
index 0000000..e76f61f
--- /dev/null
+++ b/docs/models/typeseparate.md
@@ -0,0 +1,8 @@
+# TypeSeparate
+
+
+## Values
+
+| Name | Value |
+| ---------- | ---------- |
+| `SEPARATE` | separate |
\ No newline at end of file
diff --git a/docs/models/typeusemainsigner.md b/docs/models/typeusemainsigner.md
new file mode 100644
index 0000000..35b1a62
--- /dev/null
+++ b/docs/models/typeusemainsigner.md
@@ -0,0 +1,8 @@
+# TypeUseMainSigner
+
+
+## Values
+
+| Name | Value |
+| ----------------- | ----------------- |
+| `USE_MAIN_SIGNER` | use_main_signer |
\ No newline at end of file
diff --git a/docs/models/validationstatus.md b/docs/models/validationstatus.md
deleted file mode 100644
index 821dbae..0000000
--- a/docs/models/validationstatus.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# ValidationStatus
-
-
-## Fields
-
-| Field | Type | Required | Description |
-| ------------------ | ------------------ | ------------------ | ------------------ |
-| `code` | *Optional[str]* | :heavy_minus_sign: | N/A |
-| `explanation` | *Optional[str]* | :heavy_minus_sign: | N/A |
\ No newline at end of file
diff --git a/docs/models/verificationreport.md b/docs/models/verificationreport.md
deleted file mode 100644
index 40858b1..0000000
--- a/docs/models/verificationreport.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# VerificationReport
-
-
-## Fields
-
-| Field | Type | Required | Description | Example |
-| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `validation_status` | List[[models.ValidationStatus](../models/validationstatus.md)] | :heavy_minus_sign: | N/A | |
-| `summary` | [Optional[models.Summary]](../models/summary.md) | :heavy_minus_sign: | N/A | |
-| `__pydantic_extra__` | Dict[str, *Any*] | :heavy_minus_sign: | N/A | {
"report": {
"validationStatus": [
{
"code": "claim.signature.validated",
"explanation": "Claim signature validated"
}
],
"summary": {
"isTrusted": true,
"signer": "CN=Que Signing Service"
}
}
} |
\ No newline at end of file
diff --git a/docs/models/verifyrequest.md b/docs/models/verifyrequest.md
index bab8226..eb049a9 100644
--- a/docs/models/verifyrequest.md
+++ b/docs/models/verifyrequest.md
@@ -1,9 +1,16 @@
# VerifyRequest
+Request to verify the C2PA manifest embedded in a digital asset. The asset is processed using memory-efficient streaming to temporary storage.
+
## Fields
-| Field | Type | Required | Description |
-| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `asset` | [models.AssetRefDto](../models/assetrefdto.md) | :heavy_check_mark: | A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object. |
-| `mode` | [Optional[models.VerifyRequestMode]](../models/verifyrequestmode.md) | :heavy_minus_sign: | The level of detail to return in the verification report.
* `summary`: A high-level pass/fail result. Fastest option.
* `info`: Basic information about the manifest and its claims.
* `detailed`: In-depth details of all assertions and claims.
* `tree`: A hierarchical view of the manifest's ingredient relationships.
|
\ No newline at end of file
+| Field | Type | Required | Description | Example |
+| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `asset` | [models.AssetRefDto](../models/assetrefdto.md) | :heavy_check_mark: | A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage. | |
+| `mode` | *Optional[str]* | :heavy_minus_sign: | The level of detail to return in the verification report.
* `summary`: A high-level pass/fail result with basic trust status. Fastest option for simple validation.
* `info`: Basic information about the manifest, claims, and signing entities.
* `detailed`: Comprehensive details of all assertions, claims, signatures, and validation steps.
* `tree`: Hierarchical view of the manifest's ingredient relationships and provenance chain.
| detailed |
+| `allow_remote_manifests` | *Optional[bool]* | :heavy_minus_sign: | Whether to allow fetching and validating remote manifests referenced in the asset's C2PA data. | false |
+| `allow_insecure_remote_http` | *Optional[bool]* | :heavy_minus_sign: | Whether to allow HTTP (non-HTTPS) URLs when fetching remote manifest resources. Disabled by default for security. | false |
+| `include_certificates` | *Optional[bool]* | :heavy_minus_sign: | Whether to include full certificate chains and cryptographic details in the verification report. | true |
+| `cawg` | [Optional[models.CawgVerifyDto]](../models/cawgverifydto.md) | :heavy_minus_sign: | Options controlling CAWG identity validation behavior during verification. | |
+| `limits` | [Optional[models.LimitsDto]](../models/limitsdto.md) | :heavy_minus_sign: | Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling. | |
\ No newline at end of file
diff --git a/docs/models/verifyrequestmode.md b/docs/models/verifyrequestmode.md
deleted file mode 100644
index 3f1c6ef..0000000
--- a/docs/models/verifyrequestmode.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# VerifyRequestMode
-
-The level of detail to return in the verification report.
-* `summary`: A high-level pass/fail result. Fastest option.
-* `info`: Basic information about the manifest and its claims.
-* `detailed`: In-depth details of all assertions and claims.
-* `tree`: A hierarchical view of the manifest's ingredient relationships.
-
-
-
-## Values
-
-| Name | Value |
-| ---------- | ---------- |
-| `INFO` | info |
-| `DETAILED` | detailed |
-| `TREE` | tree |
-| `SUMMARY` | summary |
\ No newline at end of file
diff --git a/docs/models/verifyresponse.md b/docs/models/verifyresponse.md
index e0474ba..390a903 100644
--- a/docs/models/verifyresponse.md
+++ b/docs/models/verifyresponse.md
@@ -1,8 +1,10 @@
# VerifyResponse
+The result of a C2PA manifest verification operation.
+
## Fields
-| Field | Type | Required | Description | Example |
-| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `report` | [models.VerificationReport](../models/verificationreport.md) | :heavy_check_mark: | N/A | {
"report": {
"validationStatus": [
{
"code": "claim.signature.validated",
"explanation": "Claim signature validated"
}
],
"summary": {
"isTrusted": true,
"signer": "CN=Que Signing Service"
}
}
} |
\ No newline at end of file
+| Field | Type | Required | Description |
+| ----------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
+| `report` | *str* | :heavy_check_mark: | JSON string containing the verification report from the C2PA engine. The structure varies based on the verification mode requested. |
\ No newline at end of file
diff --git a/docs/sdks/assetmanagement/README.md b/docs/sdks/assetmanagement/README.md
index 5541f70..eab103d 100644
--- a/docs/sdks/assetmanagement/README.md
+++ b/docs/sdks/assetmanagement/README.md
@@ -7,11 +7,20 @@ Helper endpoints for handling asset uploads.
### Available Operations
-* [get_presigned_url](#get_presigned_url) - Get an S3 presigned URL for uploads
+* [get_presigned_url](#get_presigned_url) - Get an S3 presigned URL for secure uploads
## get_presigned_url
-Generates a temporary, secure URL that a client can use to upload a large asset directly to S3. This is the recommended workflow for assets larger than a few megabytes to avoid sending large payloads through the API server.
+Generates a temporary, cryptographically signed URL that allows secure direct upload of assets to S3 without exposing AWS credentials.
+
+This is the recommended approach for uploading assets, especially large files, as it:
+- Avoids sending large payloads through the API server
+- Provides secure, time-limited access to S3
+- Enables resumable uploads for better reliability
+- Reduces API server memory usage and network overhead
+
+Use the returned URL to make a PUT request with your asset file, then use the returned key for subsequent sign/verify operations.
+
### Example Usage
diff --git a/docs/sdks/que/README.md b/docs/sdks/que/README.md
index c18781f..c43a25a 100644
--- a/docs/sdks/que/README.md
+++ b/docs/sdks/que/README.md
@@ -2,16 +2,23 @@
## Overview
-Que API: Welcome to the Que Public HTTP API. Our platform provides robust tools for working with C2PA (Coalition for Content Provenance and Authenticity) manifests, enabling you to sign and verify digital assets to ensure their authenticity and provenance.
+Que API: Welcome to the Que Public HTTP API for C2PA (Content Authenticity Initiative) provenance management.
+
+Our platform provides robust tools for working with digital asset provenance through C2PA manifests, enabling you to sign and verify digital assets to ensure their authenticity, origin, and processing history.
**Key Features:**
-* **Verify**: Inspect and validate C2PA manifests embedded in assets.
-* **Sign**: Embed C2PA manifests into your assets with a server-side signature.
-* **Trust Management**: Retrieve the current C2PA trust list.
+* **Memory-Efficient Streaming**: Assets are processed using streaming techniques to minimize memory usage, supporting large files efficiently
+* **Verify**: Inspect and validate C2PA manifests embedded in assets with multiple detail levels
+* **Sign**: Embed comprehensive C2PA manifests into your assets with server-side cryptographic signatures
+* **Trust Management**: Retrieve and validate against current trust lists containing trusted certificate authorities and manufacturers
+* **Secure Uploads**: Direct-to-S3 uploads via presigned URLs for large assets
**Authentication:**
All endpoints (except for `/healthz`) are secured and require an API key to be passed in the `x-api-key` header.
+**Processing Architecture:**
+Assets are streamed from S3 or URLs to temporary storage during processing to ensure O(chunk_size) memory usage instead of O(file_size), enabling efficient handling of large files on containerized platforms.
+
Usage of this API is tracked via Firehose for billing and monitoring purposes.
@@ -25,14 +32,17 @@ Find more detailed documentation and tutorials here.
## verify_asset
-Analyzes a digital asset (e.g., an image) to find, validate, and report on any embedded C2PA manifests. This allows you to confirm the asset's provenance and authenticity.
+Analyzes a digital asset to find, validate, and report on any embedded C2PA manifests. This allows you to confirm the asset's provenance, authenticity, and processing history.
+
+The asset is processed using memory-efficient streaming to temporary storage during verification. Returns detailed validation results including trust status, signer information, and any validation failures.
+
### Example Usage
```python
import os
-from que_media import Que, models
+from que_media import Que
with Que(
@@ -40,8 +50,14 @@ with Que(
) as que:
res = que.verify_asset(asset={
- "url": "https://example.com/images/provenance-image.jpg",
- }, mode=models.VerifyRequestMode.DETAILED)
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode="summary", allow_remote_manifests=False, allow_insecure_remote_http=False, include_certificates=True, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
# Handle response
print(res)
@@ -50,11 +66,16 @@ with Que(
### Parameters
-| Parameter | Type | Required | Description |
-| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `asset` | [models.AssetRefDto](../../models/assetrefdto.md) | :heavy_check_mark: | A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object. |
-| `mode` | [Optional[models.VerifyRequestMode]](../../models/verifyrequestmode.md) | :heavy_minus_sign: | The level of detail to return in the verification report.
* `summary`: A high-level pass/fail result. Fastest option.
* `info`: Basic information about the manifest and its claims.
* `detailed`: In-depth details of all assertions and claims.
* `tree`: A hierarchical view of the manifest's ingredient relationships.
|
-| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.md) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. |
+| Parameter | Type | Required | Description | Example |
+| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `asset` | [models.AssetRefDto](../../models/assetrefdto.md) | :heavy_check_mark: | A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage. | |
+| `mode` | *Optional[str]* | :heavy_minus_sign: | The level of detail to return in the verification report.
* `summary`: A high-level pass/fail result with basic trust status. Fastest option for simple validation.
* `info`: Basic information about the manifest, claims, and signing entities.
* `detailed`: Comprehensive details of all assertions, claims, signatures, and validation steps.
* `tree`: Hierarchical view of the manifest's ingredient relationships and provenance chain.
| detailed |
+| `allow_remote_manifests` | *Optional[bool]* | :heavy_minus_sign: | Whether to allow fetching and validating remote manifests referenced in the asset's C2PA data. | false |
+| `allow_insecure_remote_http` | *Optional[bool]* | :heavy_minus_sign: | Whether to allow HTTP (non-HTTPS) URLs when fetching remote manifest resources. Disabled by default for security. | false |
+| `include_certificates` | *Optional[bool]* | :heavy_minus_sign: | Whether to include full certificate chains and cryptographic details in the verification report. | true |
+| `cawg` | [Optional[models.CawgVerifyDto]](../../models/cawgverifydto.md) | :heavy_minus_sign: | Options controlling CAWG identity validation behavior during verification. | |
+| `limits` | [Optional[models.LimitsDto]](../../models/limitsdto.md) | :heavy_minus_sign: | Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling. | |
+| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.md) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. | |
### Response
@@ -71,7 +92,10 @@ with Que(
## sign_asset
-Embeds a C2PA manifest into a digital asset and signs it using a server-side key. This cryptographically links the asset to its provenance information.
+Embeds a C2PA manifest into a digital asset and signs it using a server-side cryptographic key. The asset is processed using memory-efficient streaming to temporary storage before signing.
+
+This operation cryptographically links the asset to its provenance information, creating an immutable record of the asset's origin, authorship, and any processing history.
+
### Example Usage
@@ -86,8 +110,14 @@ with Que(
) as que:
res = que.sign_asset(asset={
- "b64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=",
- }, mode=models.SignRequestMode.SERVER_MEASURE, manifest_json={})
+ "bucket": "que-assets-dev",
+ "key": "uploads/photo.jpg",
+ }, mode=models.Mode.SERVER_MEASURE, manifest_json="{\"title\":\"Original Photograph\",\"assertions\":[{\"label\":\"stds.schema-org.CreativeWork\",\"data\":{\"@context\":\"https://schema.org\",\"@type\":\"CreativeWork\",\"author\":[{\"@type\":\"Person\",\"name\":\"Jane Photographer\"}]}}]}", allow_insecure_remote_http=False, limits={
+ "max_asset_size_bytes": 104857600,
+ "max_output_size_bytes": 104857600,
+ "max_stream_copy_bytes": 104857600,
+ "stream_timeout_ms": 30000,
+ })
# Handle response
print(res)
@@ -96,12 +126,15 @@ with Que(
### Parameters
-| Parameter | Type | Required | Description |
-| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `asset` | [models.AssetRefDto](../../models/assetrefdto.md) | :heavy_check_mark: | A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object. |
-| `mode` | [models.SignRequestMode](../../models/signrequestmode.md) | :heavy_check_mark: | : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.
The signing mode to use.
* `server_measure`: The server will download the asset, calculate its hash, and embed the manifest. Requires `manifest_json`.
* `client_hash`: The client provides the asset hash directly. (Not yet implemented).
|
-| `manifest_json` | [Optional[models.ManifestJSON]](../../models/manifestjson.md) | :heavy_minus_sign: | The C2PA manifest to embed in the asset. This is required when `mode` is `server_measure`. |
-| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.md) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. |
+| Parameter | Type | Required | Description | Example |
+| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `asset` | [models.AssetRefDto](../../models/assetrefdto.md) | :heavy_check_mark: | A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage. | |
+| `mode` | [models.Mode](../../models/mode.md) | :heavy_check_mark: | The signing mode to use.
* `server_measure`: The server streams the asset, calculates its hash, and embeds the manifest. Requires `manifest_json`. This is the primary signing mode.
* `client_hash`: The client provides the asset hash directly for offline signing. (Not yet implemented).
| server_measure |
+| `manifest_json` | *Optional[str]* | :heavy_minus_sign: | JSON string containing the manifest to embed in the asset as a C2PA claim. This defines the provenance information and assertions about the asset. Required when `mode` is `server_measure`. | {"title":"Original Photograph","format":"image/jpeg","assertions":[{"label":"stds.schema-org.CreativeWork","data":{"@context":"https://schema.org","@type":"CreativeWork","author":[{"@type":"Person","name":"Jane Photographer"}]}}]} |
+| `cawg` | [Optional[models.CawgIdentityDto]](../../models/cawgidentitydto.md) | :heavy_minus_sign: | Configuration to add a CAWG identity assertion during signing. Presence of this object enables CAWG. | |
+| `allow_insecure_remote_http` | *Optional[bool]* | :heavy_minus_sign: | Whether to allow HTTP (non-HTTPS) URLs for remote manifest resources. Disabled by default for security. | false |
+| `limits` | [Optional[models.LimitsDto]](../../models/limitsdto.md) | :heavy_minus_sign: | Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling. | |
+| `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.md) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. | |
### Response
diff --git a/docs/sdks/utility/README.md b/docs/sdks/utility/README.md
index eb5893b..d2eedfd 100644
--- a/docs/sdks/utility/README.md
+++ b/docs/sdks/utility/README.md
@@ -51,7 +51,15 @@ with Que(
## get_trust_list
-Fetches the latest C2PA trust list, which includes trusted certificate authorities and hardware manufacturers. This list is used by verifiers to determine if a signature on a manifest is from a trusted source.
+Fetches the latest C2PA trust list containing trusted certificate authorities, hardware manufacturers, and trust policies.
+
+The trust list is used during manifest verification to:
+- Validate signer certificates against trusted Certificate Authorities
+- Verify hardware manufacturer claims for camera-captured content
+- Apply trust policies for different validation scenarios
+
+Trust lists are versioned and should be refreshed periodically as new trusted entities are added or certificates expire.
+
### Example Usage
diff --git a/pyproject.toml b/pyproject.toml
index 540e195..6053a72 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -3,13 +3,14 @@ name = "que_media"
version = "0.1.0"
description = "Python Client SDK Generated by Speakeasy."
authors = [{ name = "Speakeasy" },]
-readme = "README.md"
+readme = "README-PYPI.md"
requires-python = ">=3.9.2"
dependencies = [
"httpcore >=1.0.9",
"httpx >=0.28.1",
"pydantic >=2.11.2",
]
+urls.repository = "https://github.com/QuePlatform/PythonSDK.git"
[dependency-groups]
dev = [
diff --git a/scripts/prepare_readme.py b/scripts/prepare_readme.py
new file mode 100644
index 0000000..cac943f
--- /dev/null
+++ b/scripts/prepare_readme.py
@@ -0,0 +1,35 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+import re
+import shutil
+
+try:
+ with open("README.md", "r", encoding="utf-8") as rh:
+ readme_contents = rh.read()
+ GITHUB_URL = "https://github.com/QuePlatform/PythonSDK.git"
+ GITHUB_URL = (
+ GITHUB_URL[: -len(".git")] if GITHUB_URL.endswith(".git") else GITHUB_URL
+ )
+ REPO_SUBDIR = ""
+ # links on PyPI should have absolute URLs
+ readme_contents = re.sub(
+ r"(\[[^\]]+\]\()((?!https?:)[^\)]+)(\))",
+ lambda m: m.group(1)
+ + GITHUB_URL
+ + "/blob/master/"
+ + REPO_SUBDIR
+ + m.group(2)
+ + m.group(3),
+ readme_contents,
+ )
+
+ 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 ie:
+ print("Failed to copy README.md to README-PYPI.md")
+ print(ie)
diff --git a/scripts/publish.sh b/scripts/publish.sh
index ef28dc1..c35748f 100755
--- a/scripts/publish.sh
+++ b/scripts/publish.sh
@@ -1,4 +1,6 @@
#!/usr/bin/env bash
+uv run python scripts/prepare_readme.py
+
uv build
uv publish --token $PYPI_TOKEN
diff --git a/src/que_media/_hooks/__init__.py b/src/que_media/_hooks/__init__.py
index 2ee66cd..e763be4 100644
--- a/src/que_media/_hooks/__init__.py
+++ b/src/que_media/_hooks/__init__.py
@@ -2,4 +2,3 @@
from .sdkhooks import *
from .types import *
-from .registration import *
diff --git a/src/que_media/_hooks/sdkhooks.py b/src/que_media/_hooks/sdkhooks.py
index 0eb8aac..f2a823d 100644
--- a/src/que_media/_hooks/sdkhooks.py
+++ b/src/que_media/_hooks/sdkhooks.py
@@ -11,7 +11,6 @@
AfterErrorHook,
Hooks,
)
-from .registration import init_hooks
from typing import List, Optional, Tuple
from que_media.sdkconfiguration import SDKConfiguration
@@ -22,7 +21,6 @@ def __init__(self) -> None:
self.before_request_hooks: List[BeforeRequestHook] = []
self.after_success_hooks: List[AfterSuccessHook] = []
self.after_error_hooks: List[AfterErrorHook] = []
- init_hooks(self)
def register_sdk_init_hook(self, hook: SDKInitHook) -> None:
self.sdk_init_hooks.append(hook)
diff --git a/src/que_media/_version.py b/src/que_media/_version.py
index 67bb279..1af5242 100644
--- a/src/que_media/_version.py
+++ b/src/que_media/_version.py
@@ -3,10 +3,10 @@
import importlib.metadata
__title__: str = "que_media"
-__version__: str = "0.0.2"
+__version__: str = "0.1.0"
__openapi_doc_version__: str = "1.0.0"
-__gen_version__: str = "2.687.1"
-__user_agent__: str = "speakeasy-sdk/python 0.0.2 2.687.1 1.0.0 que_media"
+__gen_version__: str = "2.707.0"
+__user_agent__: str = "speakeasy-sdk/python 0.1.0 2.707.0 1.0.0 que_media"
try:
if __package__ is not None:
diff --git a/src/que_media/asset_management.py b/src/que_media/asset_management.py
index 0c4fa3f..eff3776 100644
--- a/src/que_media/asset_management.py
+++ b/src/que_media/asset_management.py
@@ -20,9 +20,18 @@ def get_presigned_url(
timeout_ms: Optional[int] = None,
http_headers: Optional[Mapping[str, str]] = None,
) -> models.GetPresignedURLResponse:
- r"""Get an S3 presigned URL for uploads
+ r"""Get an S3 presigned URL for secure uploads
+
+ Generates a temporary, cryptographically signed URL that allows secure direct upload of assets to S3 without exposing AWS credentials.
+
+ This is the recommended approach for uploading assets, especially large files, as it:
+ - Avoids sending large payloads through the API server
+ - Provides secure, time-limited access to S3
+ - Enables resumable uploads for better reliability
+ - Reduces API server memory usage and network overhead
+
+ Use the returned URL to make a PUT request with your asset file, then use the returned key for subsequent sign/verify operations.
- Generates a temporary, secure URL that a client can use to upload a large asset directly to S3. This is the recommended workflow for assets larger than a few megabytes to avoid sending large payloads through the API server.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
@@ -115,9 +124,18 @@ async def get_presigned_url_async(
timeout_ms: Optional[int] = None,
http_headers: Optional[Mapping[str, str]] = None,
) -> models.GetPresignedURLResponse:
- r"""Get an S3 presigned URL for uploads
+ r"""Get an S3 presigned URL for secure uploads
+
+ Generates a temporary, cryptographically signed URL that allows secure direct upload of assets to S3 without exposing AWS credentials.
+
+ This is the recommended approach for uploading assets, especially large files, as it:
+ - Avoids sending large payloads through the API server
+ - Provides secure, time-limited access to S3
+ - Enables resumable uploads for better reliability
+ - Reduces API server memory usage and network overhead
+
+ Use the returned URL to make a PUT request with your asset file, then use the returned key for subsequent sign/verify operations.
- Generates a temporary, secure URL that a client can use to upload a large asset directly to S3. This is the recommended workflow for assets larger than a few megabytes to avoid sending large payloads through the API server.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
diff --git a/src/que_media/basesdk.py b/src/que_media/basesdk.py
index 1e95b9e..bade018 100644
--- a/src/que_media/basesdk.py
+++ b/src/que_media/basesdk.py
@@ -15,9 +15,19 @@
class BaseSDK:
sdk_configuration: SDKConfiguration
+ parent_ref: Optional[object] = None
+ """
+ Reference to the root SDK instance, if any. This will prevent it from
+ being garbage collected while there are active streams.
+ """
- def __init__(self, sdk_config: SDKConfiguration) -> None:
+ def __init__(
+ self,
+ sdk_config: SDKConfiguration,
+ parent_ref: Optional[object] = None,
+ ) -> None:
self.sdk_configuration = sdk_config
+ self.parent_ref = parent_ref
def _get_url(self, base_url, url_variables):
sdk_url, sdk_variables = self.sdk_configuration.get_server_details()
diff --git a/src/que_media/errors/__init__.py b/src/que_media/errors/__init__.py
index 8412738..bdddc7e 100644
--- a/src/que_media/errors/__init__.py
+++ b/src/que_media/errors/__init__.py
@@ -1,14 +1,15 @@
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+from .queerror import QueError
from typing import TYPE_CHECKING
from importlib import import_module
import builtins
+import sys
if TYPE_CHECKING:
from .no_response_error import NoResponseError
from .problemresponse_error import ProblemResponseError, ProblemResponseErrorData
from .quedefaulterror import QueDefaultError
- from .queerror import QueError
from .responsevalidationerror import ResponseValidationError
__all__ = [
@@ -25,11 +26,22 @@
"ProblemResponseError": ".problemresponse_error",
"ProblemResponseErrorData": ".problemresponse_error",
"QueDefaultError": ".quedefaulterror",
- "QueError": ".queerror",
"ResponseValidationError": ".responsevalidationerror",
}
+def dynamic_import(modname, retries=3):
+ for attempt in range(retries):
+ try:
+ return import_module(modname, __package__)
+ except KeyError:
+ # Clear any half-initialized module and retry
+ sys.modules.pop(modname, None)
+ if attempt == retries - 1:
+ break
+ raise KeyError(f"Failed to import module '{modname}' after {retries} attempts")
+
+
def __getattr__(attr_name: str) -> object:
module_name = _dynamic_imports.get(attr_name)
if module_name is None:
@@ -38,7 +50,7 @@ def __getattr__(attr_name: str) -> object:
)
try:
- module = import_module(module_name, __package__)
+ module = dynamic_import(module_name)
result = getattr(module, attr_name)
return result
except ImportError as e:
diff --git a/src/que_media/errors/no_response_error.py b/src/que_media/errors/no_response_error.py
index f98beea..b710ea2 100644
--- a/src/que_media/errors/no_response_error.py
+++ b/src/que_media/errors/no_response_error.py
@@ -1,12 +1,16 @@
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+from dataclasses import dataclass
+
+
+@dataclass(frozen=True)
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
+ object.__setattr__(self, "message", message)
super().__init__(message)
def __str__(self):
diff --git a/src/que_media/errors/problemresponse_error.py b/src/que_media/errors/problemresponse_error.py
index 6208c1b..c9fcb01 100644
--- a/src/que_media/errors/problemresponse_error.py
+++ b/src/que_media/errors/problemresponse_error.py
@@ -1,6 +1,7 @@
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
from __future__ import annotations
+from dataclasses import dataclass, field
import httpx
from que_media.errors import QueError
from que_media.models import problemresponse_error as models_problemresponse_error
@@ -22,10 +23,11 @@ class ProblemResponseErrorData(BaseModel):
details: OptionalNullable[models_problemresponse_error.Details] = UNSET
+@dataclass(frozen=True)
class ProblemResponseError(QueError):
r"""An RFC 7807 problem details response."""
- data: ProblemResponseErrorData
+ data: ProblemResponseErrorData = field(hash=False)
def __init__(
self,
@@ -35,4 +37,4 @@ def __init__(
):
message = body or raw_response.text
super().__init__(message, raw_response, body)
- self.data = data
+ object.__setattr__(self, "data", data)
diff --git a/src/que_media/errors/quedefaulterror.py b/src/que_media/errors/quedefaulterror.py
index e3821c6..93a9db8 100644
--- a/src/que_media/errors/quedefaulterror.py
+++ b/src/que_media/errors/quedefaulterror.py
@@ -2,12 +2,14 @@
import httpx
from typing import Optional
+from dataclasses import dataclass
from que_media.errors import QueError
MAX_MESSAGE_LEN = 10_000
+@dataclass(frozen=True)
class QueDefaultError(QueError):
"""The fallback error class if no more specific error class is matched."""
diff --git a/src/que_media/errors/queerror.py b/src/que_media/errors/queerror.py
index 0a48c1a..7f6f1c3 100644
--- a/src/que_media/errors/queerror.py
+++ b/src/que_media/errors/queerror.py
@@ -2,25 +2,29 @@
import httpx
from typing import Optional
+from dataclasses import dataclass, field
+@dataclass(frozen=True)
class QueError(Exception):
"""The base class for all HTTP error responses."""
message: str
status_code: int
body: str
- headers: httpx.Headers
- raw_response: httpx.Response
+ headers: httpx.Headers = field(hash=False)
+ raw_response: httpx.Response = field(hash=False)
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
+ object.__setattr__(self, "message", message)
+ object.__setattr__(self, "status_code", raw_response.status_code)
+ object.__setattr__(
+ self, "body", body if body is not None else raw_response.text
+ )
+ object.__setattr__(self, "headers", raw_response.headers)
+ object.__setattr__(self, "raw_response", raw_response)
def __str__(self):
return self.message
diff --git a/src/que_media/errors/responsevalidationerror.py b/src/que_media/errors/responsevalidationerror.py
index 9883dae..1acc3b6 100644
--- a/src/que_media/errors/responsevalidationerror.py
+++ b/src/que_media/errors/responsevalidationerror.py
@@ -2,10 +2,12 @@
import httpx
from typing import Optional
+from dataclasses import dataclass
from que_media.errors import QueError
+@dataclass(frozen=True)
class ResponseValidationError(QueError):
"""Error raised when there is a type mismatch between the response data and the expected Pydantic model."""
diff --git a/src/que_media/models/__init__.py b/src/que_media/models/__init__.py
index 3f928d9..e4fecac 100644
--- a/src/que_media/models/__init__.py
+++ b/src/que_media/models/__init__.py
@@ -3,30 +3,51 @@
from typing import TYPE_CHECKING
from importlib import import_module
import builtins
+import sys
if TYPE_CHECKING:
from .assetrefdto import AssetRefDto, AssetRefDtoTypedDict
- from .bytesbase64 import BytesBase64, BytesBase64TypedDict
+ from .cawgidentitydto import (
+ CawgIdentityDto,
+ CawgIdentityDtoTypedDict,
+ Signer,
+ SignerSeparate,
+ SignerSeparateTypedDict,
+ SignerTypedDict,
+ SignerUseMainSigner,
+ SignerUseMainSignerTypedDict,
+ SigningAlg,
+ TypeSeparate,
+ TypeUseMainSigner,
+ )
+ from .cawgverifydto import CawgVerifyDto, CawgVerifyDtoTypedDict
from .getpresignedurlop import (
GetPresignedURLResponse,
GetPresignedURLResponseTypedDict,
)
from .gettrustlistop import GetTrustListResponse, GetTrustListResponseTypedDict
from .healthzresponse import HealthzResponse, HealthzResponseTypedDict
+ from .limitsdto import LimitsDto, LimitsDtoTypedDict
from .presignedurl import PresignedURL, PresignedURLTypedDict
from .presignresponse import PresignResponse, PresignResponseTypedDict
from .problemresponse_error import Details, DetailsTypedDict
from .s3 import S3, S3TypedDict
from .security import Security, SecurityTypedDict
from .signassetop import SignAssetResponse, SignAssetResponseTypedDict
- from .signrequest import (
- ManifestJSON,
- ManifestJSONTypedDict,
- SignRequest,
- SignRequestMode,
- SignRequestTypedDict,
+ from .signerrefdto import (
+ SignerRefDto,
+ SignerRefDtoEnv,
+ SignerRefDtoEnvTypedDict,
+ SignerRefDtoLocal,
+ SignerRefDtoLocalTypedDict,
+ SignerRefDtoTypedDict,
+ TypeEnv,
+ TypeLocal,
)
+ from .signrequest import Mode, SignRequest, SignRequestTypedDict
from .signresponse import (
+ Alg,
+ Assurance,
Evidence,
EvidenceTypedDict,
SignResponse,
@@ -35,30 +56,28 @@
from .trustlistresponse import (
Data,
DataTypedDict,
+ Default,
Policy,
PolicyTypedDict,
TrustListResponse,
TrustListResponseTypedDict,
)
- from .verificationreport import (
- Summary,
- SummaryTypedDict,
- ValidationStatus,
- ValidationStatusTypedDict,
- VerificationReport,
- VerificationReportTypedDict,
- )
from .verifyassetop import VerifyAssetResponse, VerifyAssetResponseTypedDict
- from .verifyrequest import VerifyRequest, VerifyRequestMode, VerifyRequestTypedDict
+ from .verifyrequest import VerifyRequest, VerifyRequestTypedDict
from .verifyresponse import VerifyResponse, VerifyResponseTypedDict
__all__ = [
+ "Alg",
"AssetRefDto",
"AssetRefDtoTypedDict",
- "BytesBase64",
- "BytesBase64TypedDict",
+ "Assurance",
+ "CawgIdentityDto",
+ "CawgIdentityDtoTypedDict",
+ "CawgVerifyDto",
+ "CawgVerifyDtoTypedDict",
"Data",
"DataTypedDict",
+ "Default",
"Details",
"DetailsTypedDict",
"Evidence",
@@ -69,8 +88,9 @@
"GetTrustListResponseTypedDict",
"HealthzResponse",
"HealthzResponseTypedDict",
- "ManifestJSON",
- "ManifestJSONTypedDict",
+ "LimitsDto",
+ "LimitsDtoTypedDict",
+ "Mode",
"Policy",
"PolicyTypedDict",
"PresignResponse",
@@ -84,22 +104,31 @@
"SignAssetResponse",
"SignAssetResponseTypedDict",
"SignRequest",
- "SignRequestMode",
"SignRequestTypedDict",
"SignResponse",
"SignResponseTypedDict",
- "Summary",
- "SummaryTypedDict",
+ "Signer",
+ "SignerRefDto",
+ "SignerRefDtoEnv",
+ "SignerRefDtoEnvTypedDict",
+ "SignerRefDtoLocal",
+ "SignerRefDtoLocalTypedDict",
+ "SignerRefDtoTypedDict",
+ "SignerSeparate",
+ "SignerSeparateTypedDict",
+ "SignerTypedDict",
+ "SignerUseMainSigner",
+ "SignerUseMainSignerTypedDict",
+ "SigningAlg",
"TrustListResponse",
"TrustListResponseTypedDict",
- "ValidationStatus",
- "ValidationStatusTypedDict",
- "VerificationReport",
- "VerificationReportTypedDict",
+ "TypeEnv",
+ "TypeLocal",
+ "TypeSeparate",
+ "TypeUseMainSigner",
"VerifyAssetResponse",
"VerifyAssetResponseTypedDict",
"VerifyRequest",
- "VerifyRequestMode",
"VerifyRequestTypedDict",
"VerifyResponse",
"VerifyResponseTypedDict",
@@ -108,14 +137,27 @@
_dynamic_imports: dict[str, str] = {
"AssetRefDto": ".assetrefdto",
"AssetRefDtoTypedDict": ".assetrefdto",
- "BytesBase64": ".bytesbase64",
- "BytesBase64TypedDict": ".bytesbase64",
+ "CawgIdentityDto": ".cawgidentitydto",
+ "CawgIdentityDtoTypedDict": ".cawgidentitydto",
+ "Signer": ".cawgidentitydto",
+ "SignerSeparate": ".cawgidentitydto",
+ "SignerSeparateTypedDict": ".cawgidentitydto",
+ "SignerTypedDict": ".cawgidentitydto",
+ "SignerUseMainSigner": ".cawgidentitydto",
+ "SignerUseMainSignerTypedDict": ".cawgidentitydto",
+ "SigningAlg": ".cawgidentitydto",
+ "TypeSeparate": ".cawgidentitydto",
+ "TypeUseMainSigner": ".cawgidentitydto",
+ "CawgVerifyDto": ".cawgverifydto",
+ "CawgVerifyDtoTypedDict": ".cawgverifydto",
"GetPresignedURLResponse": ".getpresignedurlop",
"GetPresignedURLResponseTypedDict": ".getpresignedurlop",
"GetTrustListResponse": ".gettrustlistop",
"GetTrustListResponseTypedDict": ".gettrustlistop",
"HealthzResponse": ".healthzresponse",
"HealthzResponseTypedDict": ".healthzresponse",
+ "LimitsDto": ".limitsdto",
+ "LimitsDtoTypedDict": ".limitsdto",
"PresignedURL": ".presignedurl",
"PresignedURLTypedDict": ".presignedurl",
"PresignResponse": ".presignresponse",
@@ -128,37 +170,51 @@
"SecurityTypedDict": ".security",
"SignAssetResponse": ".signassetop",
"SignAssetResponseTypedDict": ".signassetop",
- "ManifestJSON": ".signrequest",
- "ManifestJSONTypedDict": ".signrequest",
+ "SignerRefDto": ".signerrefdto",
+ "SignerRefDtoEnv": ".signerrefdto",
+ "SignerRefDtoEnvTypedDict": ".signerrefdto",
+ "SignerRefDtoLocal": ".signerrefdto",
+ "SignerRefDtoLocalTypedDict": ".signerrefdto",
+ "SignerRefDtoTypedDict": ".signerrefdto",
+ "TypeEnv": ".signerrefdto",
+ "TypeLocal": ".signerrefdto",
+ "Mode": ".signrequest",
"SignRequest": ".signrequest",
- "SignRequestMode": ".signrequest",
"SignRequestTypedDict": ".signrequest",
+ "Alg": ".signresponse",
+ "Assurance": ".signresponse",
"Evidence": ".signresponse",
"EvidenceTypedDict": ".signresponse",
"SignResponse": ".signresponse",
"SignResponseTypedDict": ".signresponse",
"Data": ".trustlistresponse",
"DataTypedDict": ".trustlistresponse",
+ "Default": ".trustlistresponse",
"Policy": ".trustlistresponse",
"PolicyTypedDict": ".trustlistresponse",
"TrustListResponse": ".trustlistresponse",
"TrustListResponseTypedDict": ".trustlistresponse",
- "Summary": ".verificationreport",
- "SummaryTypedDict": ".verificationreport",
- "ValidationStatus": ".verificationreport",
- "ValidationStatusTypedDict": ".verificationreport",
- "VerificationReport": ".verificationreport",
- "VerificationReportTypedDict": ".verificationreport",
"VerifyAssetResponse": ".verifyassetop",
"VerifyAssetResponseTypedDict": ".verifyassetop",
"VerifyRequest": ".verifyrequest",
- "VerifyRequestMode": ".verifyrequest",
"VerifyRequestTypedDict": ".verifyrequest",
"VerifyResponse": ".verifyresponse",
"VerifyResponseTypedDict": ".verifyresponse",
}
+def dynamic_import(modname, retries=3):
+ for attempt in range(retries):
+ try:
+ return import_module(modname, __package__)
+ except KeyError:
+ # Clear any half-initialized module and retry
+ sys.modules.pop(modname, None)
+ if attempt == retries - 1:
+ break
+ raise KeyError(f"Failed to import module '{modname}' after {retries} attempts")
+
+
def __getattr__(attr_name: str) -> object:
module_name = _dynamic_imports.get(attr_name)
if module_name is None:
@@ -167,7 +223,7 @@ def __getattr__(attr_name: str) -> object:
)
try:
- module = import_module(module_name, __package__)
+ module = dynamic_import(module_name)
result = getattr(module, attr_name)
return result
except ImportError as e:
diff --git a/src/que_media/models/assetrefdto.py b/src/que_media/models/assetrefdto.py
index d667351..5d90cc0 100644
--- a/src/que_media/models/assetrefdto.py
+++ b/src/que_media/models/assetrefdto.py
@@ -1,7 +1,6 @@
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
from __future__ import annotations
-from .bytesbase64 import BytesBase64, BytesBase64TypedDict
from .presignedurl import PresignedURL, PresignedURLTypedDict
from .s3 import S3, S3TypedDict
from typing import Union
@@ -9,11 +8,10 @@
AssetRefDtoTypedDict = TypeAliasType(
- "AssetRefDtoTypedDict",
- Union[BytesBase64TypedDict, PresignedURLTypedDict, S3TypedDict],
+ "AssetRefDtoTypedDict", Union[PresignedURLTypedDict, S3TypedDict]
)
-r"""A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object."""
+r"""A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage."""
-AssetRefDto = TypeAliasType("AssetRefDto", Union[BytesBase64, PresignedURL, S3])
-r"""A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object."""
+AssetRefDto = TypeAliasType("AssetRefDto", Union[PresignedURL, S3])
+r"""A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage."""
diff --git a/src/que_media/models/bytesbase64.py b/src/que_media/models/bytesbase64.py
deleted file mode 100644
index 2a26001..0000000
--- a/src/que_media/models/bytesbase64.py
+++ /dev/null
@@ -1,19 +0,0 @@
-"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
-
-from __future__ import annotations
-from que_media.types import BaseModel
-from typing_extensions import TypedDict
-
-
-class BytesBase64TypedDict(TypedDict):
- r"""An asset provided as a Base64-encoded string. Suitable for small files."""
-
- b64: str
- r"""The raw bytes of the asset, encoded in Base64."""
-
-
-class BytesBase64(BaseModel):
- r"""An asset provided as a Base64-encoded string. Suitable for small files."""
-
- b64: str
- r"""The raw bytes of the asset, encoded in Base64."""
diff --git a/src/que_media/models/cawgidentitydto.py b/src/que_media/models/cawgidentitydto.py
new file mode 100644
index 0000000..924dbda
--- /dev/null
+++ b/src/que_media/models/cawgidentitydto.py
@@ -0,0 +1,81 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+from .signerrefdto import SignerRefDto, SignerRefDtoTypedDict
+from enum import Enum
+from que_media.types import BaseModel
+from typing import List, Optional, Union
+from typing_extensions import NotRequired, TypeAliasType, TypedDict
+
+
+class TypeSeparate(str, Enum):
+ SEPARATE = "separate"
+
+
+class SignerSeparateTypedDict(TypedDict):
+ type: TypeSeparate
+ signer: SignerRefDtoTypedDict
+ r"""Reference to credentials for signing."""
+
+
+class SignerSeparate(BaseModel):
+ type: TypeSeparate
+
+ signer: SignerRefDto
+ r"""Reference to credentials for signing."""
+
+
+class TypeUseMainSigner(str, Enum):
+ USE_MAIN_SIGNER = "use_main_signer"
+
+
+class SignerUseMainSignerTypedDict(TypedDict):
+ type: TypeUseMainSigner
+
+
+class SignerUseMainSigner(BaseModel):
+ type: TypeUseMainSigner
+
+
+SignerTypedDict = TypeAliasType(
+ "SignerTypedDict", Union[SignerUseMainSignerTypedDict, SignerSeparateTypedDict]
+)
+
+
+Signer = TypeAliasType("Signer", Union[SignerUseMainSigner, SignerSeparate])
+
+
+class SigningAlg(str, Enum):
+ r"""Algorithm used for the CAWG identity signature."""
+
+ ED25519 = "ed25519"
+ ES256 = "es256"
+ ES384 = "es384"
+ PS256 = "ps256"
+
+
+class CawgIdentityDtoTypedDict(TypedDict):
+ r"""Configuration to add a CAWG identity assertion during signing. Presence of this object enables CAWG."""
+
+ signer: NotRequired[SignerTypedDict]
+ signing_alg: NotRequired[SigningAlg]
+ r"""Algorithm used for the CAWG identity signature."""
+ referenced_assertions: NotRequired[List[str]]
+ r"""Assertion labels that the identity assertion should reference."""
+ timestamper: NotRequired[str]
+ r"""Timestamper to use (\"digicert\" or \"custom:\")."""
+
+
+class CawgIdentityDto(BaseModel):
+ r"""Configuration to add a CAWG identity assertion during signing. Presence of this object enables CAWG."""
+
+ signer: Optional[Signer] = None
+
+ signing_alg: Optional[SigningAlg] = SigningAlg.ED25519
+ r"""Algorithm used for the CAWG identity signature."""
+
+ referenced_assertions: Optional[List[str]] = None
+ r"""Assertion labels that the identity assertion should reference."""
+
+ timestamper: Optional[str] = None
+ r"""Timestamper to use (\"digicert\" or \"custom:\")."""
diff --git a/src/que_media/models/cawgverifydto.py b/src/que_media/models/cawgverifydto.py
new file mode 100644
index 0000000..adb0f21
--- /dev/null
+++ b/src/que_media/models/cawgverifydto.py
@@ -0,0 +1,26 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+import pydantic
+from que_media.types import BaseModel
+from typing import Optional
+from typing_extensions import Annotated, NotRequired, TypedDict
+
+
+class CawgVerifyDtoTypedDict(TypedDict):
+ r"""Options controlling CAWG identity validation behavior during verification."""
+
+ validate_: NotRequired[bool]
+ r"""Whether to run CAWG identity validation."""
+ require_valid_identity: NotRequired[bool]
+ r"""Whether to fail verification if CAWG identity is missing/invalid."""
+
+
+class CawgVerifyDto(BaseModel):
+ r"""Options controlling CAWG identity validation behavior during verification."""
+
+ validate_: Annotated[Optional[bool], pydantic.Field(alias="validate")] = True
+ r"""Whether to run CAWG identity validation."""
+
+ require_valid_identity: Optional[bool] = False
+ r"""Whether to fail verification if CAWG identity is missing/invalid."""
diff --git a/src/que_media/models/limitsdto.py b/src/que_media/models/limitsdto.py
new file mode 100644
index 0000000..ac13541
--- /dev/null
+++ b/src/que_media/models/limitsdto.py
@@ -0,0 +1,35 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+from que_media.types import BaseModel
+from typing import Optional
+from typing_extensions import NotRequired, TypedDict
+
+
+class LimitsDtoTypedDict(TypedDict):
+ r"""Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling."""
+
+ max_asset_size_bytes: NotRequired[int]
+ r"""Maximum allowed size for the asset file in bytes. This limit is enforced during the streaming download phase to prevent memory exhaustion."""
+ max_output_size_bytes: NotRequired[int]
+ r"""Maximum allowed size for the output (signed asset) in bytes. This prevents excessive storage usage for signed assets."""
+ max_stream_copy_bytes: NotRequired[int]
+ r"""Maximum allowed bytes for stream copying operations during processing. This limits the amount of data that can be buffered in memory during the signing/verification process."""
+ stream_timeout_ms: NotRequired[int]
+ r"""Timeout for streaming operations in milliseconds. This prevents hanging operations when downloading from slow sources."""
+
+
+class LimitsDto(BaseModel):
+ r"""Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling."""
+
+ max_asset_size_bytes: Optional[int] = None
+ r"""Maximum allowed size for the asset file in bytes. This limit is enforced during the streaming download phase to prevent memory exhaustion."""
+
+ max_output_size_bytes: Optional[int] = None
+ r"""Maximum allowed size for the output (signed asset) in bytes. This prevents excessive storage usage for signed assets."""
+
+ max_stream_copy_bytes: Optional[int] = None
+ r"""Maximum allowed bytes for stream copying operations during processing. This limits the amount of data that can be buffered in memory during the signing/verification process."""
+
+ stream_timeout_ms: Optional[int] = None
+ r"""Timeout for streaming operations in milliseconds. This prevents hanging operations when downloading from slow sources."""
diff --git a/src/que_media/models/presignedurl.py b/src/que_media/models/presignedurl.py
index 01b8b07..2d13f43 100644
--- a/src/que_media/models/presignedurl.py
+++ b/src/que_media/models/presignedurl.py
@@ -6,14 +6,14 @@
class PresignedURLTypedDict(TypedDict):
- r"""An asset located at a publicly accessible or presigned URL."""
+ r"""An asset accessible via HTTP/HTTPS URL. The URL must be enabled via the ALLOW_URL_ASSETS environment variable. The service will stream the file to temporary storage during processing."""
url: str
- r"""The URL where the asset can be downloaded."""
+ r"""The HTTP/HTTPS URL of the asset. Must be publicly accessible."""
class PresignedURL(BaseModel):
- r"""An asset located at a publicly accessible or presigned URL."""
+ r"""An asset accessible via HTTP/HTTPS URL. The URL must be enabled via the ALLOW_URL_ASSETS environment variable. The service will stream the file to temporary storage during processing."""
url: str
- r"""The URL where the asset can be downloaded."""
+ r"""The HTTP/HTTPS URL of the asset. Must be publicly accessible."""
diff --git a/src/que_media/models/presignresponse.py b/src/que_media/models/presignresponse.py
index 85bb15b..1fde3d1 100644
--- a/src/que_media/models/presignresponse.py
+++ b/src/que_media/models/presignresponse.py
@@ -6,19 +6,19 @@
class PresignResponseTypedDict(TypedDict):
- r"""A presigned URL that can be used for a temporary, authenticated upload to S3."""
+ r"""A presigned URL and object key for secure S3 upload. Use the URL to upload your asset directly to S3, then use the returned key for signing/verification operations."""
url: str
- r"""The presigned S3 URL to which the client should PUT the asset file."""
+ r"""The presigned S3 URL for direct upload. Make a PUT request to this URL with your asset file as the body. The URL is valid for a limited time (typically 15 minutes)."""
key: str
- r"""The S3 object key that the asset will have after being uploaded. This key should be used in subsequent API calls."""
+ r"""The S3 object key where your asset will be stored. Use this key in subsequent sign/verify API calls to reference the uploaded asset."""
class PresignResponse(BaseModel):
- r"""A presigned URL that can be used for a temporary, authenticated upload to S3."""
+ r"""A presigned URL and object key for secure S3 upload. Use the URL to upload your asset directly to S3, then use the returned key for signing/verification operations."""
url: str
- r"""The presigned S3 URL to which the client should PUT the asset file."""
+ r"""The presigned S3 URL for direct upload. Make a PUT request to this URL with your asset file as the body. The URL is valid for a limited time (typically 15 minutes)."""
key: str
- r"""The S3 object key that the asset will have after being uploaded. This key should be used in subsequent API calls."""
+ r"""The S3 object key where your asset will be stored. Use this key in subsequent sign/verify API calls to reference the uploaded asset."""
diff --git a/src/que_media/models/s3.py b/src/que_media/models/s3.py
index a890b90..987abf1 100644
--- a/src/que_media/models/s3.py
+++ b/src/que_media/models/s3.py
@@ -6,7 +6,7 @@
class S3TypedDict(TypedDict):
- r"""An asset located in an S3 bucket that the Que service has access to."""
+ r"""An asset located in an S3 bucket that the Que service has access to. The service will stream the file from S3 to temporary storage during processing."""
bucket: str
r"""The name of the S3 bucket."""
@@ -15,7 +15,7 @@ class S3TypedDict(TypedDict):
class S3(BaseModel):
- r"""An asset located in an S3 bucket that the Que service has access to."""
+ r"""An asset located in an S3 bucket that the Que service has access to. The service will stream the file from S3 to temporary storage during processing."""
bucket: str
r"""The name of the S3 bucket."""
diff --git a/src/que_media/models/signerrefdto.py b/src/que_media/models/signerrefdto.py
new file mode 100644
index 0000000..eba5841
--- /dev/null
+++ b/src/que_media/models/signerrefdto.py
@@ -0,0 +1,53 @@
+"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
+
+from __future__ import annotations
+from enum import Enum
+from que_media.types import BaseModel
+from typing import Union
+from typing_extensions import TypeAliasType, TypedDict
+
+
+class TypeLocal(str, Enum):
+ LOCAL = "local"
+
+
+class SignerRefDtoLocalTypedDict(TypedDict):
+ type: TypeLocal
+ cert_path: str
+ key_path: str
+
+
+class SignerRefDtoLocal(BaseModel):
+ type: TypeLocal
+
+ cert_path: str
+
+ key_path: str
+
+
+class TypeEnv(str, Enum):
+ ENV = "env"
+
+
+class SignerRefDtoEnvTypedDict(TypedDict):
+ type: TypeEnv
+ cert_var: str
+ key_var: str
+
+
+class SignerRefDtoEnv(BaseModel):
+ type: TypeEnv
+
+ cert_var: str
+
+ key_var: str
+
+
+SignerRefDtoTypedDict = TypeAliasType(
+ "SignerRefDtoTypedDict", Union[SignerRefDtoEnvTypedDict, SignerRefDtoLocalTypedDict]
+)
+r"""Reference to credentials for signing."""
+
+
+SignerRefDto = TypeAliasType("SignerRefDto", Union[SignerRefDtoEnv, SignerRefDtoLocal])
+r"""Reference to credentials for signing."""
diff --git a/src/que_media/models/signrequest.py b/src/que_media/models/signrequest.py
index 19734f6..ecbfa8a 100644
--- a/src/que_media/models/signrequest.py
+++ b/src/que_media/models/signrequest.py
@@ -2,20 +2,18 @@
from __future__ import annotations
from .assetrefdto import AssetRefDto, AssetRefDtoTypedDict
+from .cawgidentitydto import CawgIdentityDto, CawgIdentityDtoTypedDict
+from .limitsdto import LimitsDto, LimitsDtoTypedDict
from enum import Enum
-import pydantic
from que_media.types import BaseModel
from typing import Optional
-from typing_extensions import Annotated, NotRequired, TypedDict, deprecated
+from typing_extensions import NotRequired, TypedDict
-@deprecated(
- "warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
-)
-class SignRequestMode(str, Enum):
+class Mode(str, Enum):
r"""The signing mode to use.
- * `server_measure`: The server will download the asset, calculate its hash, and embed the manifest. Requires `manifest_json`.
- * `client_hash`: The client provides the asset hash directly. (Not yet implemented).
+ * `server_measure`: The server streams the asset, calculates its hash, and embeds the manifest. Requires `manifest_json`. This is the primary signing mode.
+ * `client_hash`: The client provides the asset hash directly for offline signing. (Not yet implemented).
"""
@@ -23,42 +21,48 @@ class SignRequestMode(str, Enum):
CLIENT_HASH = "client_hash"
-class ManifestJSONTypedDict(TypedDict):
- r"""The C2PA manifest to embed in the asset. This is required when `mode` is `server_measure`."""
-
-
-class ManifestJSON(BaseModel):
- r"""The C2PA manifest to embed in the asset. This is required when `mode` is `server_measure`."""
-
-
class SignRequestTypedDict(TypedDict):
+ r"""Request to sign a digital asset with a C2PA manifest. The asset is processed using memory-efficient streaming to temporary storage."""
+
asset: AssetRefDtoTypedDict
- r"""A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object."""
- mode: SignRequestMode
+ r"""A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage."""
+ mode: Mode
r"""The signing mode to use.
- * `server_measure`: The server will download the asset, calculate its hash, and embed the manifest. Requires `manifest_json`.
- * `client_hash`: The client provides the asset hash directly. (Not yet implemented).
+ * `server_measure`: The server streams the asset, calculates its hash, and embeds the manifest. Requires `manifest_json`. This is the primary signing mode.
+ * `client_hash`: The client provides the asset hash directly for offline signing. (Not yet implemented).
"""
- manifest_json: NotRequired[ManifestJSONTypedDict]
- r"""The C2PA manifest to embed in the asset. This is required when `mode` is `server_measure`."""
+ manifest_json: NotRequired[str]
+ r"""JSON string containing the manifest to embed in the asset as a C2PA claim. This defines the provenance information and assertions about the asset. Required when `mode` is `server_measure`."""
+ cawg: NotRequired[CawgIdentityDtoTypedDict]
+ r"""Configuration to add a CAWG identity assertion during signing. Presence of this object enables CAWG."""
+ allow_insecure_remote_http: NotRequired[bool]
+ r"""Whether to allow HTTP (non-HTTPS) URLs for remote manifest resources. Disabled by default for security."""
+ limits: NotRequired[LimitsDtoTypedDict]
+ r"""Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling."""
class SignRequest(BaseModel):
+ r"""Request to sign a digital asset with a C2PA manifest. The asset is processed using memory-efficient streaming to temporary storage."""
+
asset: AssetRefDto
- r"""A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object."""
-
- mode: Annotated[
- SignRequestMode,
- pydantic.Field(
- deprecated="warning: ** DEPRECATED ** - This will be removed in a future release, please migrate away from it as soon as possible."
- ),
- ]
+ r"""A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage."""
+
+ mode: Mode
r"""The signing mode to use.
- * `server_measure`: The server will download the asset, calculate its hash, and embed the manifest. Requires `manifest_json`.
- * `client_hash`: The client provides the asset hash directly. (Not yet implemented).
+ * `server_measure`: The server streams the asset, calculates its hash, and embeds the manifest. Requires `manifest_json`. This is the primary signing mode.
+ * `client_hash`: The client provides the asset hash directly for offline signing. (Not yet implemented).
"""
- manifest_json: Optional[ManifestJSON] = None
- r"""The C2PA manifest to embed in the asset. This is required when `mode` is `server_measure`."""
+ manifest_json: Optional[str] = None
+ r"""JSON string containing the manifest to embed in the asset as a C2PA claim. This defines the provenance information and assertions about the asset. Required when `mode` is `server_measure`."""
+
+ cawg: Optional[CawgIdentityDto] = None
+ r"""Configuration to add a CAWG identity assertion during signing. Presence of this object enables CAWG."""
+
+ allow_insecure_remote_http: Optional[bool] = False
+ r"""Whether to allow HTTP (non-HTTPS) URLs for remote manifest resources. Disabled by default for security."""
+
+ limits: Optional[LimitsDto] = None
+ r"""Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling."""
diff --git a/src/que_media/models/signresponse.py b/src/que_media/models/signresponse.py
index e289f82..b43278a 100644
--- a/src/que_media/models/signresponse.py
+++ b/src/que_media/models/signresponse.py
@@ -1,51 +1,73 @@
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
from __future__ import annotations
+from enum import Enum
from pydantic import model_serializer
from que_media.types import BaseModel, Nullable, OptionalNullable, UNSET, UNSET_SENTINEL
from typing_extensions import NotRequired, TypedDict
+class Assurance(str, Enum):
+ r"""The level of assurance provided by the signing process."""
+
+ SERVER_MEASURED = "server_measured"
+ CLIENT_HASH = "client_hash"
+
+
+class Alg(str, Enum):
+ r"""The cryptographic algorithm used for signing."""
+
+ ES256 = "ES256"
+ PS256 = "PS256"
+ ED25519 = "Ed25519"
+
+
class EvidenceTypedDict(TypedDict):
- r"""Metadata about the signature that was applied."""
+ r"""Cryptographic evidence about the signature that was applied."""
+
+ signer: str
+ r"""Identifier for the signing entity/key used."""
+ alg: Alg
+ r"""The cryptographic algorithm used for signing."""
class Evidence(BaseModel):
- r"""Metadata about the signature that was applied."""
+ r"""Cryptographic evidence about the signature that was applied."""
+
+ signer: str
+ r"""Identifier for the signing entity/key used."""
+
+ alg: Alg
+ r"""The cryptographic algorithm used for signing."""
class SignResponseTypedDict(TypedDict):
- r"""The result of a successful signing operation, including the signed asset."""
+ r"""The result of a successful signing operation. The signed asset is stored in S3 and the manifest is cryptographically embedded."""
- assurance: str
+ assurance: Assurance
r"""The level of assurance provided by the signing process."""
evidence: EvidenceTypedDict
- r"""Metadata about the signature that was applied."""
- asset_b64: NotRequired[Nullable[str]]
- r"""The Base64-encoded signed asset. This field is populated if the resulting asset is 3MB or less. If larger, this will be null."""
+ r"""Cryptographic evidence about the signature that was applied."""
asset_s3_uri: NotRequired[Nullable[str]]
- r"""An S3 URI for the signed asset. This field is populated if the resulting asset is larger than 3MB. If the asset is inlined in `asset_b64`, this will be null."""
+ r"""S3 URI of the signed asset. The signed asset is automatically uploaded to S3 with the embedded C2PA manifest."""
class SignResponse(BaseModel):
- r"""The result of a successful signing operation, including the signed asset."""
+ r"""The result of a successful signing operation. The signed asset is stored in S3 and the manifest is cryptographically embedded."""
- assurance: str
+ assurance: Assurance
r"""The level of assurance provided by the signing process."""
evidence: Evidence
- r"""Metadata about the signature that was applied."""
-
- asset_b64: OptionalNullable[str] = UNSET
- r"""The Base64-encoded signed asset. This field is populated if the resulting asset is 3MB or less. If larger, this will be null."""
+ r"""Cryptographic evidence about the signature that was applied."""
asset_s3_uri: OptionalNullable[str] = UNSET
- r"""An S3 URI for the signed asset. This field is populated if the resulting asset is larger than 3MB. If the asset is inlined in `asset_b64`, this will be null."""
+ r"""S3 URI of the signed asset. The signed asset is automatically uploaded to S3 with the embedded C2PA manifest."""
@model_serializer(mode="wrap")
def serialize_model(self, handler):
- optional_fields = ["asset_b64", "asset_s3_uri"]
- nullable_fields = ["asset_b64", "asset_s3_uri"]
+ optional_fields = ["asset_s3_uri"]
+ nullable_fields = ["asset_s3_uri"]
null_default_fields = []
serialized = handler(self)
diff --git a/src/que_media/models/trustlistresponse.py b/src/que_media/models/trustlistresponse.py
index 391255a..0500b03 100644
--- a/src/que_media/models/trustlistresponse.py
+++ b/src/que_media/models/trustlistresponse.py
@@ -2,46 +2,76 @@
from __future__ import annotations
from datetime import datetime
+from enum import Enum
from que_media.types import BaseModel
from typing import List
from typing_extensions import TypedDict
+class Default(str, Enum):
+ r"""Default trust policy when no specific rule applies."""
+
+ ALLOW = "allow"
+ DENY = "deny"
+
+
class PolicyTypedDict(TypedDict):
- default: str
+ r"""Trust policy configuration defining default trust behavior."""
+
+ default: Default
+ r"""Default trust policy when no specific rule applies."""
class Policy(BaseModel):
- default: str
+ r"""Trust policy configuration defining default trust behavior."""
+
+ default: Default
+ r"""Default trust policy when no specific rule applies."""
class DataTypedDict(TypedDict):
+ r"""The trust list data containing certificates and policies."""
+
manufacturers: List[str]
+ r"""List of trusted hardware manufacturers whose devices can create trusted provenance."""
cas: List[str]
+ r"""List of trusted Certificate Authority certificates in PEM format."""
policy: PolicyTypedDict
+ r"""Trust policy configuration defining default trust behavior."""
class Data(BaseModel):
+ r"""The trust list data containing certificates and policies."""
+
manufacturers: List[str]
+ r"""List of trusted hardware manufacturers whose devices can create trusted provenance."""
cas: List[str]
+ r"""List of trusted Certificate Authority certificates in PEM format."""
policy: Policy
+ r"""Trust policy configuration defining default trust behavior."""
class TrustListResponseTypedDict(TypedDict):
- r"""The C2PA trust list bundle, containing trusted certificate authorities and manufacturers."""
+ r"""The current C2PA trust list containing trusted certificate authorities, hardware manufacturers, and trust policies used for manifest verification."""
version: str
+ r"""Version identifier for this trust list bundle."""
issued_at: datetime
+ r"""Timestamp when this trust list was issued."""
data: DataTypedDict
+ r"""The trust list data containing certificates and policies."""
class TrustListResponse(BaseModel):
- r"""The C2PA trust list bundle, containing trusted certificate authorities and manufacturers."""
+ r"""The current C2PA trust list containing trusted certificate authorities, hardware manufacturers, and trust policies used for manifest verification."""
version: str
+ r"""Version identifier for this trust list bundle."""
issued_at: datetime
+ r"""Timestamp when this trust list was issued."""
data: Data
+ r"""The trust list data containing certificates and policies."""
diff --git a/src/que_media/models/verificationreport.py b/src/que_media/models/verificationreport.py
deleted file mode 100644
index 011fad8..0000000
--- a/src/que_media/models/verificationreport.py
+++ /dev/null
@@ -1,56 +0,0 @@
-"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
-
-from __future__ import annotations
-import pydantic
-from pydantic import ConfigDict
-from que_media.types import BaseModel
-from typing import Any, Dict, List, Optional
-from typing_extensions import Annotated, NotRequired, TypedDict
-
-
-class ValidationStatusTypedDict(TypedDict):
- code: NotRequired[str]
- explanation: NotRequired[str]
-
-
-class ValidationStatus(BaseModel):
- code: Optional[str] = None
-
- explanation: Optional[str] = None
-
-
-class SummaryTypedDict(TypedDict):
- is_trusted: NotRequired[bool]
- signer: NotRequired[str]
-
-
-class Summary(BaseModel):
- is_trusted: Annotated[Optional[bool], pydantic.Field(alias="isTrusted")] = None
-
- signer: Optional[str] = None
-
-
-class VerificationReportTypedDict(TypedDict):
- validation_status: NotRequired[List[ValidationStatusTypedDict]]
- summary: NotRequired[SummaryTypedDict]
-
-
-class VerificationReport(BaseModel):
- model_config = ConfigDict(
- populate_by_name=True, arbitrary_types_allowed=True, extra="allow"
- )
- __pydantic_extra__: Dict[str, Any] = pydantic.Field(init=False)
-
- validation_status: Annotated[
- Optional[List[ValidationStatus]], pydantic.Field(alias="validationStatus")
- ] = None
-
- summary: Optional[Summary] = None
-
- @property
- def additional_properties(self):
- return self.__pydantic_extra__
-
- @additional_properties.setter
- def additional_properties(self, value):
- self.__pydantic_extra__ = value # pyright: ignore[reportIncompatibleVariableOverride]
diff --git a/src/que_media/models/verifyrequest.py b/src/que_media/models/verifyrequest.py
index 261a9b0..dc625ad 100644
--- a/src/que_media/models/verifyrequest.py
+++ b/src/que_media/models/verifyrequest.py
@@ -2,49 +2,64 @@
from __future__ import annotations
from .assetrefdto import AssetRefDto, AssetRefDtoTypedDict
-from enum import Enum
+from .cawgverifydto import CawgVerifyDto, CawgVerifyDtoTypedDict
+from .limitsdto import LimitsDto, LimitsDtoTypedDict
from que_media.types import BaseModel
from typing import Optional
from typing_extensions import NotRequired, TypedDict
-class VerifyRequestMode(str, Enum):
- r"""The level of detail to return in the verification report.
- * `summary`: A high-level pass/fail result. Fastest option.
- * `info`: Basic information about the manifest and its claims.
- * `detailed`: In-depth details of all assertions and claims.
- * `tree`: A hierarchical view of the manifest's ingredient relationships.
-
- """
-
- INFO = "info"
- DETAILED = "detailed"
- TREE = "tree"
- SUMMARY = "summary"
-
-
class VerifyRequestTypedDict(TypedDict):
+ r"""Request to verify the C2PA manifest embedded in a digital asset. The asset is processed using memory-efficient streaming to temporary storage."""
+
asset: AssetRefDtoTypedDict
- r"""A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object."""
- mode: NotRequired[VerifyRequestMode]
+ r"""A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage."""
+ mode: NotRequired[str]
r"""The level of detail to return in the verification report.
- * `summary`: A high-level pass/fail result. Fastest option.
- * `info`: Basic information about the manifest and its claims.
- * `detailed`: In-depth details of all assertions and claims.
- * `tree`: A hierarchical view of the manifest's ingredient relationships.
+ * `summary`: A high-level pass/fail result with basic trust status. Fastest option for simple validation.
+ * `info`: Basic information about the manifest, claims, and signing entities.
+ * `detailed`: Comprehensive details of all assertions, claims, signatures, and validation steps.
+ * `tree`: Hierarchical view of the manifest's ingredient relationships and provenance chain.
"""
+ allow_remote_manifests: NotRequired[bool]
+ r"""Whether to allow fetching and validating remote manifests referenced in the asset's C2PA data."""
+ allow_insecure_remote_http: NotRequired[bool]
+ r"""Whether to allow HTTP (non-HTTPS) URLs when fetching remote manifest resources. Disabled by default for security."""
+ include_certificates: NotRequired[bool]
+ r"""Whether to include full certificate chains and cryptographic details in the verification report."""
+ cawg: NotRequired[CawgVerifyDtoTypedDict]
+ r"""Options controlling CAWG identity validation behavior during verification."""
+ limits: NotRequired[LimitsDtoTypedDict]
+ r"""Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling."""
class VerifyRequest(BaseModel):
+ r"""Request to verify the C2PA manifest embedded in a digital asset. The asset is processed using memory-efficient streaming to temporary storage."""
+
asset: AssetRefDto
- r"""A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object."""
+ r"""A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage."""
- mode: Optional[VerifyRequestMode] = VerifyRequestMode.SUMMARY
+ mode: Optional[str] = "summary"
r"""The level of detail to return in the verification report.
- * `summary`: A high-level pass/fail result. Fastest option.
- * `info`: Basic information about the manifest and its claims.
- * `detailed`: In-depth details of all assertions and claims.
- * `tree`: A hierarchical view of the manifest's ingredient relationships.
+ * `summary`: A high-level pass/fail result with basic trust status. Fastest option for simple validation.
+ * `info`: Basic information about the manifest, claims, and signing entities.
+ * `detailed`: Comprehensive details of all assertions, claims, signatures, and validation steps.
+ * `tree`: Hierarchical view of the manifest's ingredient relationships and provenance chain.
"""
+
+ allow_remote_manifests: Optional[bool] = False
+ r"""Whether to allow fetching and validating remote manifests referenced in the asset's C2PA data."""
+
+ allow_insecure_remote_http: Optional[bool] = False
+ r"""Whether to allow HTTP (non-HTTPS) URLs when fetching remote manifest resources. Disabled by default for security."""
+
+ include_certificates: Optional[bool] = False
+ r"""Whether to include full certificate chains and cryptographic details in the verification report."""
+
+ cawg: Optional[CawgVerifyDto] = None
+ r"""Options controlling CAWG identity validation behavior during verification."""
+
+ limits: Optional[LimitsDto] = None
+ r"""Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling."""
diff --git a/src/que_media/models/verifyresponse.py b/src/que_media/models/verifyresponse.py
index 9706db9..02106bc 100644
--- a/src/que_media/models/verifyresponse.py
+++ b/src/que_media/models/verifyresponse.py
@@ -1,14 +1,19 @@
"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""
from __future__ import annotations
-from .verificationreport import VerificationReport, VerificationReportTypedDict
from que_media.types import BaseModel
from typing_extensions import TypedDict
class VerifyResponseTypedDict(TypedDict):
- report: VerificationReportTypedDict
+ r"""The result of a C2PA manifest verification operation."""
+
+ report: str
+ r"""JSON string containing the verification report from the C2PA engine. The structure varies based on the verification mode requested."""
class VerifyResponse(BaseModel):
- report: VerificationReport
+ r"""The result of a C2PA manifest verification operation."""
+
+ report: str
+ r"""JSON string containing the verification report from the C2PA engine. The structure varies based on the verification mode requested."""
diff --git a/src/que_media/sdk.py b/src/que_media/sdk.py
index c1d2d25..3dc02e2 100644
--- a/src/que_media/sdk.py
+++ b/src/que_media/sdk.py
@@ -12,6 +12,7 @@
from que_media.types import OptionalNullable, UNSET
from que_media.utils import get_security_from_env
from que_media.utils.unmarshal_json_response import unmarshal_json_response
+import sys
from typing import (
Any,
Callable,
@@ -31,16 +32,23 @@
class Que(BaseSDK):
- r"""Que API: Welcome to the Que Public HTTP API. Our platform provides robust tools for working with C2PA (Coalition for Content Provenance and Authenticity) manifests, enabling you to sign and verify digital assets to ensure their authenticity and provenance.
+ r"""Que API: Welcome to the Que Public HTTP API for C2PA (Content Authenticity Initiative) provenance management.
+
+ Our platform provides robust tools for working with digital asset provenance through C2PA manifests, enabling you to sign and verify digital assets to ensure their authenticity, origin, and processing history.
**Key Features:**
- * **Verify**: Inspect and validate C2PA manifests embedded in assets.
- * **Sign**: Embed C2PA manifests into your assets with a server-side signature.
- * **Trust Management**: Retrieve the current C2PA trust list.
+ * **Memory-Efficient Streaming**: Assets are processed using streaming techniques to minimize memory usage, supporting large files efficiently
+ * **Verify**: Inspect and validate C2PA manifests embedded in assets with multiple detail levels
+ * **Sign**: Embed comprehensive C2PA manifests into your assets with server-side cryptographic signatures
+ * **Trust Management**: Retrieve and validate against current trust lists containing trusted certificate authorities and manufacturers
+ * **Secure Uploads**: Direct-to-S3 uploads via presigned URLs for large assets
**Authentication:**
All endpoints (except for `/healthz`) are secured and require an API key to be passed in the `x-api-key` header.
+ **Processing Architecture:**
+ Assets are streamed from S3 or URLs to temporary storage during processing to ensure O(chunk_size) memory usage instead of O(file_size), enabling efficient handling of large files on containerized platforms.
+
Usage of this API is tracked via Firehose for billing and monitoring purposes.
https://docs.addque.org - Find more detailed documentation and tutorials here.
@@ -134,6 +142,7 @@ def __init__(
timeout_ms=timeout_ms,
debug_logger=debug_logger,
),
+ parent_ref=self,
)
hooks = SDKHooks()
@@ -153,13 +162,24 @@ def __init__(
self.sdk_configuration.async_client_supplied,
)
+ def dynamic_import(self, modname, retries=3):
+ for attempt in range(retries):
+ try:
+ return importlib.import_module(modname)
+ except KeyError:
+ # Clear any half-initialized module and retry
+ sys.modules.pop(modname, None)
+ if attempt == retries - 1:
+ break
+ raise KeyError(f"Failed to import module '{modname}' after {retries} attempts")
+
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)
+ module = self.dynamic_import(module_path)
klass = getattr(module, class_name)
- instance = klass(self.sdk_configuration)
+ instance = klass(self.sdk_configuration, parent_ref=self)
setattr(self, name, instance)
return instance
except ImportError as e:
@@ -206,7 +226,14 @@ def verify_asset(
self,
*,
asset: Union[models.AssetRefDto, models.AssetRefDtoTypedDict],
- mode: Optional[models.VerifyRequestMode] = models.VerifyRequestMode.SUMMARY,
+ mode: Optional[str] = "summary",
+ allow_remote_manifests: Optional[bool] = False,
+ allow_insecure_remote_http: Optional[bool] = False,
+ include_certificates: Optional[bool] = False,
+ cawg: Optional[
+ Union[models.CawgVerifyDto, models.CawgVerifyDtoTypedDict]
+ ] = None,
+ limits: Optional[Union[models.LimitsDto, models.LimitsDtoTypedDict]] = None,
retries: OptionalNullable[utils.RetryConfig] = UNSET,
server_url: Optional[str] = None,
timeout_ms: Optional[int] = None,
@@ -214,10 +241,18 @@ def verify_asset(
) -> models.VerifyAssetResponse:
r"""Verify the C2PA manifest of an asset
- Analyzes a digital asset (e.g., an image) to find, validate, and report on any embedded C2PA manifests. This allows you to confirm the asset's provenance and authenticity.
+ Analyzes a digital asset to find, validate, and report on any embedded C2PA manifests. This allows you to confirm the asset's provenance, authenticity, and processing history.
+
+ The asset is processed using memory-efficient streaming to temporary storage during verification. Returns detailed validation results including trust status, signer information, and any validation failures.
- :param asset: A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object.
- :param mode: The level of detail to return in the verification report. * `summary`: A high-level pass/fail result. Fastest option. * `info`: Basic information about the manifest and its claims. * `detailed`: In-depth details of all assertions and claims. * `tree`: A hierarchical view of the manifest's ingredient relationships.
+
+ :param asset: A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage.
+ :param mode: The level of detail to return in the verification report. * `summary`: A high-level pass/fail result with basic trust status. Fastest option for simple validation. * `info`: Basic information about the manifest, claims, and signing entities. * `detailed`: Comprehensive details of all assertions, claims, signatures, and validation steps. * `tree`: Hierarchical view of the manifest's ingredient relationships and provenance chain.
+ :param allow_remote_manifests: Whether to allow fetching and validating remote manifests referenced in the asset's C2PA data.
+ :param allow_insecure_remote_http: Whether to allow HTTP (non-HTTPS) URLs when fetching remote manifest resources. Disabled by default for security.
+ :param include_certificates: Whether to include full certificate chains and cryptographic details in the verification report.
+ :param cawg: Options controlling CAWG identity validation behavior during verification.
+ :param limits: Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
@@ -236,6 +271,11 @@ def verify_asset(
request = models.VerifyRequest(
asset=utils.get_pydantic_model(asset, models.AssetRefDto),
mode=mode,
+ allow_remote_manifests=allow_remote_manifests,
+ allow_insecure_remote_http=allow_insecure_remote_http,
+ include_certificates=include_certificates,
+ cawg=utils.get_pydantic_model(cawg, Optional[models.CawgVerifyDto]),
+ limits=utils.get_pydantic_model(limits, Optional[models.LimitsDto]),
)
req = self._build_request(
@@ -316,7 +356,14 @@ async def verify_asset_async(
self,
*,
asset: Union[models.AssetRefDto, models.AssetRefDtoTypedDict],
- mode: Optional[models.VerifyRequestMode] = models.VerifyRequestMode.SUMMARY,
+ mode: Optional[str] = "summary",
+ allow_remote_manifests: Optional[bool] = False,
+ allow_insecure_remote_http: Optional[bool] = False,
+ include_certificates: Optional[bool] = False,
+ cawg: Optional[
+ Union[models.CawgVerifyDto, models.CawgVerifyDtoTypedDict]
+ ] = None,
+ limits: Optional[Union[models.LimitsDto, models.LimitsDtoTypedDict]] = None,
retries: OptionalNullable[utils.RetryConfig] = UNSET,
server_url: Optional[str] = None,
timeout_ms: Optional[int] = None,
@@ -324,10 +371,18 @@ async def verify_asset_async(
) -> models.VerifyAssetResponse:
r"""Verify the C2PA manifest of an asset
- Analyzes a digital asset (e.g., an image) to find, validate, and report on any embedded C2PA manifests. This allows you to confirm the asset's provenance and authenticity.
+ Analyzes a digital asset to find, validate, and report on any embedded C2PA manifests. This allows you to confirm the asset's provenance, authenticity, and processing history.
- :param asset: A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object.
- :param mode: The level of detail to return in the verification report. * `summary`: A high-level pass/fail result. Fastest option. * `info`: Basic information about the manifest and its claims. * `detailed`: In-depth details of all assertions and claims. * `tree`: A hierarchical view of the manifest's ingredient relationships.
+ The asset is processed using memory-efficient streaming to temporary storage during verification. Returns detailed validation results including trust status, signer information, and any validation failures.
+
+
+ :param asset: A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage.
+ :param mode: The level of detail to return in the verification report. * `summary`: A high-level pass/fail result with basic trust status. Fastest option for simple validation. * `info`: Basic information about the manifest, claims, and signing entities. * `detailed`: Comprehensive details of all assertions, claims, signatures, and validation steps. * `tree`: Hierarchical view of the manifest's ingredient relationships and provenance chain.
+ :param allow_remote_manifests: Whether to allow fetching and validating remote manifests referenced in the asset's C2PA data.
+ :param allow_insecure_remote_http: Whether to allow HTTP (non-HTTPS) URLs when fetching remote manifest resources. Disabled by default for security.
+ :param include_certificates: Whether to include full certificate chains and cryptographic details in the verification report.
+ :param cawg: Options controlling CAWG identity validation behavior during verification.
+ :param limits: Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
@@ -346,6 +401,11 @@ async def verify_asset_async(
request = models.VerifyRequest(
asset=utils.get_pydantic_model(asset, models.AssetRefDto),
mode=mode,
+ allow_remote_manifests=allow_remote_manifests,
+ allow_insecure_remote_http=allow_insecure_remote_http,
+ include_certificates=include_certificates,
+ cawg=utils.get_pydantic_model(cawg, Optional[models.CawgVerifyDto]),
+ limits=utils.get_pydantic_model(limits, Optional[models.LimitsDto]),
)
req = self._build_request_async(
@@ -426,10 +486,13 @@ def sign_asset(
self,
*,
asset: Union[models.AssetRefDto, models.AssetRefDtoTypedDict],
- mode: models.SignRequestMode,
- manifest_json: Optional[
- Union[models.ManifestJSON, models.ManifestJSONTypedDict]
+ mode: models.Mode,
+ manifest_json: Optional[str] = None,
+ cawg: Optional[
+ Union[models.CawgIdentityDto, models.CawgIdentityDtoTypedDict]
] = None,
+ allow_insecure_remote_http: Optional[bool] = False,
+ limits: Optional[Union[models.LimitsDto, models.LimitsDtoTypedDict]] = None,
retries: OptionalNullable[utils.RetryConfig] = UNSET,
server_url: Optional[str] = None,
timeout_ms: Optional[int] = None,
@@ -437,11 +500,17 @@ def sign_asset(
) -> models.SignAssetResponse:
r"""Sign an asset with a C2PA manifest
- Embeds a C2PA manifest into a digital asset and signs it using a server-side key. This cryptographically links the asset to its provenance information.
+ Embeds a C2PA manifest into a digital asset and signs it using a server-side cryptographic key. The asset is processed using memory-efficient streaming to temporary storage before signing.
+
+ This operation cryptographically links the asset to its provenance information, creating an immutable record of the asset's origin, authorship, and any processing history.
+
- :param asset: A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object.
- :param mode: The signing mode to use. * `server_measure`: The server will download the asset, calculate its hash, and embed the manifest. Requires `manifest_json`. * `client_hash`: The client provides the asset hash directly. (Not yet implemented).
- :param manifest_json: The C2PA manifest to embed in the asset. This is required when `mode` is `server_measure`.
+ :param asset: A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage.
+ :param mode: The signing mode to use. * `server_measure`: The server streams the asset, calculates its hash, and embeds the manifest. Requires `manifest_json`. This is the primary signing mode. * `client_hash`: The client provides the asset hash directly for offline signing. (Not yet implemented).
+ :param manifest_json: JSON string containing the manifest to embed in the asset as a C2PA claim. This defines the provenance information and assertions about the asset. Required when `mode` is `server_measure`.
+ :param cawg: Configuration to add a CAWG identity assertion during signing. Presence of this object enables CAWG.
+ :param allow_insecure_remote_http: Whether to allow HTTP (non-HTTPS) URLs for remote manifest resources. Disabled by default for security.
+ :param limits: Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
@@ -460,9 +529,10 @@ def sign_asset(
request = models.SignRequest(
asset=utils.get_pydantic_model(asset, models.AssetRefDto),
mode=mode,
- manifest_json=utils.get_pydantic_model(
- manifest_json, Optional[models.ManifestJSON]
- ),
+ manifest_json=manifest_json,
+ cawg=utils.get_pydantic_model(cawg, Optional[models.CawgIdentityDto]),
+ allow_insecure_remote_http=allow_insecure_remote_http,
+ limits=utils.get_pydantic_model(limits, Optional[models.LimitsDto]),
)
req = self._build_request(
@@ -543,10 +613,13 @@ async def sign_asset_async(
self,
*,
asset: Union[models.AssetRefDto, models.AssetRefDtoTypedDict],
- mode: models.SignRequestMode,
- manifest_json: Optional[
- Union[models.ManifestJSON, models.ManifestJSONTypedDict]
+ mode: models.Mode,
+ manifest_json: Optional[str] = None,
+ cawg: Optional[
+ Union[models.CawgIdentityDto, models.CawgIdentityDtoTypedDict]
] = None,
+ allow_insecure_remote_http: Optional[bool] = False,
+ limits: Optional[Union[models.LimitsDto, models.LimitsDtoTypedDict]] = None,
retries: OptionalNullable[utils.RetryConfig] = UNSET,
server_url: Optional[str] = None,
timeout_ms: Optional[int] = None,
@@ -554,11 +627,17 @@ async def sign_asset_async(
) -> models.SignAssetResponse:
r"""Sign an asset with a C2PA manifest
- Embeds a C2PA manifest into a digital asset and signs it using a server-side key. This cryptographically links the asset to its provenance information.
+ Embeds a C2PA manifest into a digital asset and signs it using a server-side cryptographic key. The asset is processed using memory-efficient streaming to temporary storage before signing.
+
+ This operation cryptographically links the asset to its provenance information, creating an immutable record of the asset's origin, authorship, and any processing history.
- :param asset: A reference to a digital asset. The asset can be provided inline as Base64, via a public URL, or by referencing an S3 object.
- :param mode: The signing mode to use. * `server_measure`: The server will download the asset, calculate its hash, and embed the manifest. Requires `manifest_json`. * `client_hash`: The client provides the asset hash directly. (Not yet implemented).
- :param manifest_json: The C2PA manifest to embed in the asset. This is required when `mode` is `server_measure`.
+
+ :param asset: A reference to a digital asset, either stored in S3 or accessible via URL. Files are streamed efficiently to temporary storage during processing to minimize memory usage.
+ :param mode: The signing mode to use. * `server_measure`: The server streams the asset, calculates its hash, and embeds the manifest. Requires `manifest_json`. This is the primary signing mode. * `client_hash`: The client provides the asset hash directly for offline signing. (Not yet implemented).
+ :param manifest_json: JSON string containing the manifest to embed in the asset as a C2PA claim. This defines the provenance information and assertions about the asset. Required when `mode` is `server_measure`.
+ :param cawg: Configuration to add a CAWG identity assertion during signing. Presence of this object enables CAWG.
+ :param allow_insecure_remote_http: Whether to allow HTTP (non-HTTPS) URLs for remote manifest resources. Disabled by default for security.
+ :param limits: Optional limits for processing operations to prevent resource exhaustion. These limits apply to the streaming and processing phases of asset handling.
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
:param timeout_ms: Override the default request timeout configuration for this method in milliseconds
@@ -577,9 +656,10 @@ async def sign_asset_async(
request = models.SignRequest(
asset=utils.get_pydantic_model(asset, models.AssetRefDto),
mode=mode,
- manifest_json=utils.get_pydantic_model(
- manifest_json, Optional[models.ManifestJSON]
- ),
+ manifest_json=manifest_json,
+ cawg=utils.get_pydantic_model(cawg, Optional[models.CawgIdentityDto]),
+ allow_insecure_remote_http=allow_insecure_remote_http,
+ limits=utils.get_pydantic_model(limits, Optional[models.LimitsDto]),
)
req = self._build_request_async(
diff --git a/src/que_media/utility.py b/src/que_media/utility.py
index 2cdc85f..7af3332 100644
--- a/src/que_media/utility.py
+++ b/src/que_media/utility.py
@@ -174,7 +174,15 @@ def get_trust_list(
) -> models.GetTrustListResponse:
r"""Retrieve the current C2PA trust bundle
- Fetches the latest C2PA trust list, which includes trusted certificate authorities and hardware manufacturers. This list is used by verifiers to determine if a signature on a manifest is from a trusted source.
+ Fetches the latest C2PA trust list containing trusted certificate authorities, hardware manufacturers, and trust policies.
+
+ The trust list is used during manifest verification to:
+ - Validate signer certificates against trusted Certificate Authorities
+ - Verify hardware manufacturer claims for camera-captured content
+ - Apply trust policies for different validation scenarios
+
+ Trust lists are versioned and should be refreshed periodically as new trusted entities are added or certificates expire.
+
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
@@ -269,7 +277,15 @@ async def get_trust_list_async(
) -> models.GetTrustListResponse:
r"""Retrieve the current C2PA trust bundle
- Fetches the latest C2PA trust list, which includes trusted certificate authorities and hardware manufacturers. This list is used by verifiers to determine if a signature on a manifest is from a trusted source.
+ Fetches the latest C2PA trust list containing trusted certificate authorities, hardware manufacturers, and trust policies.
+
+ The trust list is used during manifest verification to:
+ - Validate signer certificates against trusted Certificate Authorities
+ - Verify hardware manufacturer claims for camera-captured content
+ - Apply trust policies for different validation scenarios
+
+ Trust lists are versioned and should be refreshed periodically as new trusted entities are added or certificates expire.
+
:param retries: Override the default retry configuration for this method
:param server_url: Override the default server URL for this method
diff --git a/src/que_media/utils/__init__.py b/src/que_media/utils/__init__.py
index 5c2c9c2..87192dd 100644
--- a/src/que_media/utils/__init__.py
+++ b/src/que_media/utils/__init__.py
@@ -3,6 +3,7 @@
from typing import TYPE_CHECKING
from importlib import import_module
import builtins
+import sys
if TYPE_CHECKING:
from .annotations import get_discriminator
@@ -162,6 +163,18 @@
}
+def dynamic_import(modname, retries=3):
+ for attempt in range(retries):
+ try:
+ return import_module(modname, __package__)
+ except KeyError:
+ # Clear any half-initialized module and retry
+ sys.modules.pop(modname, None)
+ if attempt == retries - 1:
+ break
+ raise KeyError(f"Failed to import module '{modname}' after {retries} attempts")
+
+
def __getattr__(attr_name: str) -> object:
module_name = _dynamic_imports.get(attr_name)
if module_name is None:
@@ -170,9 +183,8 @@ def __getattr__(attr_name: str) -> object:
)
try:
- module = import_module(module_name, __package__)
- result = getattr(module, attr_name)
- return result
+ module = dynamic_import(module_name)
+ return getattr(module, attr_name)
except ImportError as e:
raise ImportError(
f"Failed to import {attr_name} from {module_name}: {e}"
diff --git a/src/que_media/utils/eventstreaming.py b/src/que_media/utils/eventstreaming.py
index 74a63f7..0969899 100644
--- a/src/que_media/utils/eventstreaming.py
+++ b/src/que_media/utils/eventstreaming.py
@@ -17,6 +17,9 @@
class EventStream(Generic[T]):
+ # Holds a reference to the SDK client to avoid it being garbage collected
+ # and cause termination of the underlying httpx client.
+ client_ref: Optional[object]
response: httpx.Response
generator: Generator[T, None, None]
@@ -25,9 +28,11 @@ def __init__(
response: httpx.Response,
decoder: Callable[[str], T],
sentinel: Optional[str] = None,
+ client_ref: Optional[object] = None,
):
self.response = response
self.generator = stream_events(response, decoder, sentinel)
+ self.client_ref = client_ref
def __iter__(self):
return self
@@ -43,6 +48,9 @@ def __exit__(self, exc_type, exc_val, exc_tb):
class EventStreamAsync(Generic[T]):
+ # Holds a reference to the SDK client to avoid it being garbage collected
+ # and cause termination of the underlying httpx client.
+ client_ref: Optional[object]
response: httpx.Response
generator: AsyncGenerator[T, None]
@@ -51,9 +59,11 @@ def __init__(
response: httpx.Response,
decoder: Callable[[str], T],
sentinel: Optional[str] = None,
+ client_ref: Optional[object] = None,
):
self.response = response
self.generator = stream_events_async(response, decoder, sentinel)
+ self.client_ref = client_ref
def __aiter__(self):
return self
diff --git a/uv.lock b/uv.lock
new file mode 100644
index 0000000..1d905ea
--- /dev/null
+++ b/uv.lock
@@ -0,0 +1,460 @@
+version = 1
+revision = 3
+requires-python = ">=3.9.2"
+resolution-markers = [
+ "python_full_version >= '3.12'",
+ "python_full_version == '3.11.*'",
+ "python_full_version < '3.11'",
+]
+
+[[package]]
+name = "annotated-types"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
+]
+
+[[package]]
+name = "anyio"
+version = "4.10.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
+ { name = "idna" },
+ { name = "sniffio" },
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f1/b4/636b3b65173d3ce9a38ef5f0522789614e590dab6a8d505340a4efe4c567/anyio-4.10.0.tar.gz", hash = "sha256:3f3fae35c96039744587aa5b8371e7e8e603c0702999535961dd336026973ba6", size = 213252, upload-time = "2025-08-04T08:54:26.451Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1", size = 107213, upload-time = "2025-08-04T08:54:24.882Z" },
+]
+
+[[package]]
+name = "astroid"
+version = "3.2.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9e/53/1067e1113ecaf58312357f2cd93063674924119d80d173adc3f6f2387aa2/astroid-3.2.4.tar.gz", hash = "sha256:0e14202810b30da1b735827f78f5157be2bbd4a7a59b7707ca0bfc2fb4c0063a", size = 397576, upload-time = "2024-07-20T12:57:43.26Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/80/96/b32bbbb46170a1c8b8b1f28c794202e25cfe743565e9d3469b8eb1e0cc05/astroid-3.2.4-py3-none-any.whl", hash = "sha256:413658a61eeca6202a59231abb473f932038fbcbf1666587f66d482083413a25", size = 276348, upload-time = "2024-07-20T12:57:40.886Z" },
+]
+
+[[package]]
+name = "certifi"
+version = "2025.8.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" },
+]
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
+]
+
+[[package]]
+name = "dill"
+version = "0.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" },
+]
+
+[[package]]
+name = "exceptiongroup"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" },
+]
+
+[[package]]
+name = "h11"
+version = "0.16.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
+]
+
+[[package]]
+name = "httpcore"
+version = "1.0.9"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "certifi" },
+ { name = "h11" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
+]
+
+[[package]]
+name = "httpx"
+version = "0.28.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "anyio" },
+ { name = "certifi" },
+ { name = "httpcore" },
+ { name = "idna" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
+]
+
+[[package]]
+name = "idna"
+version = "3.10"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
+]
+
+[[package]]
+name = "isort"
+version = "5.13.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303, upload-time = "2023-12-13T20:37:26.124Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310, upload-time = "2023-12-13T20:37:23.244Z" },
+]
+
+[[package]]
+name = "mccabe"
+version = "0.7.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658, upload-time = "2022-01-24T01:14:51.113Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" },
+]
+
+[[package]]
+name = "mypy"
+version = "1.15.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "mypy-extensions" },
+ { name = "tomli", marker = "python_full_version < '3.11'" },
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ce/43/d5e49a86afa64bd3839ea0d5b9c7103487007d728e1293f52525d6d5486a/mypy-1.15.0.tar.gz", hash = "sha256:404534629d51d3efea5c800ee7c42b72a6554d6c400e6a79eafe15d11341fd43", size = 3239717, upload-time = "2025-02-05T03:50:34.655Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/68/f8/65a7ce8d0e09b6329ad0c8d40330d100ea343bd4dd04c4f8ae26462d0a17/mypy-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:979e4e1a006511dacf628e36fadfecbcc0160a8af6ca7dad2f5025529e082c13", size = 10738433, upload-time = "2025-02-05T03:49:29.145Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/95/9c0ecb8eacfe048583706249439ff52105b3f552ea9c4024166c03224270/mypy-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c4bb0e1bd29f7d34efcccd71cf733580191e9a264a2202b0239da95984c5b559", size = 9861472, upload-time = "2025-02-05T03:49:16.986Z" },
+ { url = "https://files.pythonhosted.org/packages/84/09/9ec95e982e282e20c0d5407bc65031dfd0f0f8ecc66b69538296e06fcbee/mypy-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be68172e9fd9ad8fb876c6389f16d1c1b5f100ffa779f77b1fb2176fcc9ab95b", size = 11611424, upload-time = "2025-02-05T03:49:46.908Z" },
+ { url = "https://files.pythonhosted.org/packages/78/13/f7d14e55865036a1e6a0a69580c240f43bc1f37407fe9235c0d4ef25ffb0/mypy-1.15.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7be1e46525adfa0d97681432ee9fcd61a3964c2446795714699a998d193f1a3", size = 12365450, upload-time = "2025-02-05T03:50:05.89Z" },
+ { url = "https://files.pythonhosted.org/packages/48/e1/301a73852d40c241e915ac6d7bcd7fedd47d519246db2d7b86b9d7e7a0cb/mypy-1.15.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2e2c2e6d3593f6451b18588848e66260ff62ccca522dd231cd4dd59b0160668b", size = 12551765, upload-time = "2025-02-05T03:49:33.56Z" },
+ { url = "https://files.pythonhosted.org/packages/77/ba/c37bc323ae5fe7f3f15a28e06ab012cd0b7552886118943e90b15af31195/mypy-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:6983aae8b2f653e098edb77f893f7b6aca69f6cffb19b2cc7443f23cce5f4828", size = 9274701, upload-time = "2025-02-05T03:49:38.981Z" },
+ { url = "https://files.pythonhosted.org/packages/03/bc/f6339726c627bd7ca1ce0fa56c9ae2d0144604a319e0e339bdadafbbb599/mypy-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2922d42e16d6de288022e5ca321cd0618b238cfc5570e0263e5ba0a77dbef56f", size = 10662338, upload-time = "2025-02-05T03:50:17.287Z" },
+ { url = "https://files.pythonhosted.org/packages/e2/90/8dcf506ca1a09b0d17555cc00cd69aee402c203911410136cd716559efe7/mypy-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2ee2d57e01a7c35de00f4634ba1bbf015185b219e4dc5909e281016df43f5ee5", size = 9787540, upload-time = "2025-02-05T03:49:51.21Z" },
+ { url = "https://files.pythonhosted.org/packages/05/05/a10f9479681e5da09ef2f9426f650d7b550d4bafbef683b69aad1ba87457/mypy-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:973500e0774b85d9689715feeffcc980193086551110fd678ebe1f4342fb7c5e", size = 11538051, upload-time = "2025-02-05T03:50:20.885Z" },
+ { url = "https://files.pythonhosted.org/packages/e9/9a/1f7d18b30edd57441a6411fcbc0c6869448d1a4bacbaee60656ac0fc29c8/mypy-1.15.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a95fb17c13e29d2d5195869262f8125dfdb5c134dc8d9a9d0aecf7525b10c2c", size = 12286751, upload-time = "2025-02-05T03:49:42.408Z" },
+ { url = "https://files.pythonhosted.org/packages/72/af/19ff499b6f1dafcaf56f9881f7a965ac2f474f69f6f618b5175b044299f5/mypy-1.15.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1905f494bfd7d85a23a88c5d97840888a7bd516545fc5aaedff0267e0bb54e2f", size = 12421783, upload-time = "2025-02-05T03:49:07.707Z" },
+ { url = "https://files.pythonhosted.org/packages/96/39/11b57431a1f686c1aed54bf794870efe0f6aeca11aca281a0bd87a5ad42c/mypy-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:c9817fa23833ff189db061e6d2eff49b2f3b6ed9856b4a0a73046e41932d744f", size = 9265618, upload-time = "2025-02-05T03:49:54.581Z" },
+ { url = "https://files.pythonhosted.org/packages/98/3a/03c74331c5eb8bd025734e04c9840532226775c47a2c39b56a0c8d4f128d/mypy-1.15.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:aea39e0583d05124836ea645f412e88a5c7d0fd77a6d694b60d9b6b2d9f184fd", size = 10793981, upload-time = "2025-02-05T03:50:28.25Z" },
+ { url = "https://files.pythonhosted.org/packages/f0/1a/41759b18f2cfd568848a37c89030aeb03534411eef981df621d8fad08a1d/mypy-1.15.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f2147ab812b75e5b5499b01ade1f4a81489a147c01585cda36019102538615f", size = 9749175, upload-time = "2025-02-05T03:50:13.411Z" },
+ { url = "https://files.pythonhosted.org/packages/12/7e/873481abf1ef112c582db832740f4c11b2bfa510e829d6da29b0ab8c3f9c/mypy-1.15.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ce436f4c6d218a070048ed6a44c0bbb10cd2cc5e272b29e7845f6a2f57ee4464", size = 11455675, upload-time = "2025-02-05T03:50:31.421Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/d0/92ae4cde706923a2d3f2d6c39629134063ff64b9dedca9c1388363da072d/mypy-1.15.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8023ff13985661b50a5928fc7a5ca15f3d1affb41e5f0a9952cb68ef090b31ee", size = 12410020, upload-time = "2025-02-05T03:48:48.705Z" },
+ { url = "https://files.pythonhosted.org/packages/46/8b/df49974b337cce35f828ba6fda228152d6db45fed4c86ba56ffe442434fd/mypy-1.15.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1124a18bc11a6a62887e3e137f37f53fbae476dc36c185d549d4f837a2a6a14e", size = 12498582, upload-time = "2025-02-05T03:49:03.628Z" },
+ { url = "https://files.pythonhosted.org/packages/13/50/da5203fcf6c53044a0b699939f31075c45ae8a4cadf538a9069b165c1050/mypy-1.15.0-cp312-cp312-win_amd64.whl", hash = "sha256:171a9ca9a40cd1843abeca0e405bc1940cd9b305eaeea2dda769ba096932bb22", size = 9366614, upload-time = "2025-02-05T03:50:00.313Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/9b/fd2e05d6ffff24d912f150b87db9e364fa8282045c875654ce7e32fffa66/mypy-1.15.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93faf3fdb04768d44bf28693293f3904bbb555d076b781ad2530214ee53e3445", size = 10788592, upload-time = "2025-02-05T03:48:55.789Z" },
+ { url = "https://files.pythonhosted.org/packages/74/37/b246d711c28a03ead1fd906bbc7106659aed7c089d55fe40dd58db812628/mypy-1.15.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:811aeccadfb730024c5d3e326b2fbe9249bb7413553f15499a4050f7c30e801d", size = 9753611, upload-time = "2025-02-05T03:48:44.581Z" },
+ { url = "https://files.pythonhosted.org/packages/a6/ac/395808a92e10cfdac8003c3de9a2ab6dc7cde6c0d2a4df3df1b815ffd067/mypy-1.15.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:98b7b9b9aedb65fe628c62a6dc57f6d5088ef2dfca37903a7d9ee374d03acca5", size = 11438443, upload-time = "2025-02-05T03:49:25.514Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/8b/801aa06445d2de3895f59e476f38f3f8d610ef5d6908245f07d002676cbf/mypy-1.15.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43a7682e24b4f576d93072216bf56eeff70d9140241f9edec0c104d0c515036", size = 12402541, upload-time = "2025-02-05T03:49:57.623Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/67/5a4268782eb77344cc613a4cf23540928e41f018a9a1ec4c6882baf20ab8/mypy-1.15.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:baefc32840a9f00babd83251560e0ae1573e2f9d1b067719479bfb0e987c6357", size = 12494348, upload-time = "2025-02-05T03:48:52.361Z" },
+ { url = "https://files.pythonhosted.org/packages/83/3e/57bb447f7bbbfaabf1712d96f9df142624a386d98fb026a761532526057e/mypy-1.15.0-cp313-cp313-win_amd64.whl", hash = "sha256:b9378e2c00146c44793c98b8d5a61039a048e31f429fb0eb546d93f4b000bedf", size = 9373648, upload-time = "2025-02-05T03:49:11.395Z" },
+ { url = "https://files.pythonhosted.org/packages/5a/fa/79cf41a55b682794abe71372151dbbf856e3008f6767057229e6649d294a/mypy-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e601a7fa172c2131bff456bb3ee08a88360760d0d2f8cbd7a75a65497e2df078", size = 10737129, upload-time = "2025-02-05T03:50:24.509Z" },
+ { url = "https://files.pythonhosted.org/packages/d3/33/dd8feb2597d648de29e3da0a8bf4e1afbda472964d2a4a0052203a6f3594/mypy-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:712e962a6357634fef20412699a3655c610110e01cdaa6180acec7fc9f8513ba", size = 9856335, upload-time = "2025-02-05T03:49:36.398Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/b5/74508959c1b06b96674b364ffeb7ae5802646b32929b7701fc6b18447592/mypy-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95579473af29ab73a10bada2f9722856792a36ec5af5399b653aa28360290a5", size = 11611935, upload-time = "2025-02-05T03:49:14.154Z" },
+ { url = "https://files.pythonhosted.org/packages/6c/53/da61b9d9973efcd6507183fdad96606996191657fe79701b2c818714d573/mypy-1.15.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f8722560a14cde92fdb1e31597760dc35f9f5524cce17836c0d22841830fd5b", size = 12365827, upload-time = "2025-02-05T03:48:59.458Z" },
+ { url = "https://files.pythonhosted.org/packages/c1/72/965bd9ee89540c79a25778cc080c7e6ef40aa1eeac4d52cec7eae6eb5228/mypy-1.15.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fbb8da62dc352133d7d7ca90ed2fb0e9d42bb1a32724c287d3c76c58cbaa9c2", size = 12541924, upload-time = "2025-02-05T03:50:03.12Z" },
+ { url = "https://files.pythonhosted.org/packages/46/d0/f41645c2eb263e6c77ada7d76f894c580c9ddb20d77f0c24d34273a4dab2/mypy-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:d10d994b41fb3497719bbf866f227b3489048ea4bbbb5015357db306249f7980", size = 9271176, upload-time = "2025-02-05T03:50:10.86Z" },
+ { url = "https://files.pythonhosted.org/packages/09/4e/a7d65c7322c510de2c409ff3828b03354a7c43f5a8ed458a7a131b41c7b9/mypy-1.15.0-py3-none-any.whl", hash = "sha256:5469affef548bd1895d86d3bf10ce2b44e33d86923c29e4d675b3e323437ea3e", size = 2221777, upload-time = "2025-02-05T03:50:08.348Z" },
+]
+
+[[package]]
+name = "mypy-extensions"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" },
+]
+
+[[package]]
+name = "platformdirs"
+version = "4.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/23/e8/21db9c9987b0e728855bd57bff6984f67952bea55d6f75e055c46b5383e8/platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf", size = 21634, upload-time = "2025-08-26T14:32:04.268Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/40/4b/2028861e724d3bd36227adfa20d3fd24c3fc6d52032f4a93c133be5d17ce/platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85", size = 18654, upload-time = "2025-08-26T14:32:02.735Z" },
+]
+
+[[package]]
+name = "pydantic"
+version = "2.11.9"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "annotated-types" },
+ { name = "pydantic-core" },
+ { name = "typing-extensions" },
+ { name = "typing-inspection" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" },
+]
+
+[[package]]
+name = "pydantic-core"
+version = "2.33.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e5/92/b31726561b5dae176c2d2c2dc43a9c5bfba5d32f96f8b4c0a600dd492447/pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8", size = 2028817, upload-time = "2025-04-23T18:30:43.919Z" },
+ { url = "https://files.pythonhosted.org/packages/a3/44/3f0b95fafdaca04a483c4e685fe437c6891001bf3ce8b2fded82b9ea3aa1/pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d", size = 1861357, upload-time = "2025-04-23T18:30:46.372Z" },
+ { url = "https://files.pythonhosted.org/packages/30/97/e8f13b55766234caae05372826e8e4b3b96e7b248be3157f53237682e43c/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d", size = 1898011, upload-time = "2025-04-23T18:30:47.591Z" },
+ { url = "https://files.pythonhosted.org/packages/9b/a3/99c48cf7bafc991cc3ee66fd544c0aae8dc907b752f1dad2d79b1b5a471f/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572", size = 1982730, upload-time = "2025-04-23T18:30:49.328Z" },
+ { url = "https://files.pythonhosted.org/packages/de/8e/a5b882ec4307010a840fb8b58bd9bf65d1840c92eae7534c7441709bf54b/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02", size = 2136178, upload-time = "2025-04-23T18:30:50.907Z" },
+ { url = "https://files.pythonhosted.org/packages/e4/bb/71e35fc3ed05af6834e890edb75968e2802fe98778971ab5cba20a162315/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b", size = 2736462, upload-time = "2025-04-23T18:30:52.083Z" },
+ { url = "https://files.pythonhosted.org/packages/31/0d/c8f7593e6bc7066289bbc366f2235701dcbebcd1ff0ef8e64f6f239fb47d/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2", size = 2005652, upload-time = "2025-04-23T18:30:53.389Z" },
+ { url = "https://files.pythonhosted.org/packages/d2/7a/996d8bd75f3eda405e3dd219ff5ff0a283cd8e34add39d8ef9157e722867/pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a", size = 2113306, upload-time = "2025-04-23T18:30:54.661Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/84/daf2a6fb2db40ffda6578a7e8c5a6e9c8affb251a05c233ae37098118788/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac", size = 2073720, upload-time = "2025-04-23T18:30:56.11Z" },
+ { url = "https://files.pythonhosted.org/packages/77/fb/2258da019f4825128445ae79456a5499c032b55849dbd5bed78c95ccf163/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a", size = 2244915, upload-time = "2025-04-23T18:30:57.501Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/7a/925ff73756031289468326e355b6fa8316960d0d65f8b5d6b3a3e7866de7/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b", size = 2241884, upload-time = "2025-04-23T18:30:58.867Z" },
+ { url = "https://files.pythonhosted.org/packages/0b/b0/249ee6d2646f1cdadcb813805fe76265745c4010cf20a8eba7b0e639d9b2/pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22", size = 1910496, upload-time = "2025-04-23T18:31:00.078Z" },
+ { url = "https://files.pythonhosted.org/packages/66/ff/172ba8f12a42d4b552917aa65d1f2328990d3ccfc01d5b7c943ec084299f/pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640", size = 1955019, upload-time = "2025-04-23T18:31:01.335Z" },
+ { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584, upload-time = "2025-04-23T18:31:03.106Z" },
+ { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071, upload-time = "2025-04-23T18:31:04.621Z" },
+ { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" },
+ { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792, upload-time = "2025-04-23T18:31:07.93Z" },
+ { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338, upload-time = "2025-04-23T18:31:09.283Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998, upload-time = "2025-04-23T18:31:11.7Z" },
+ { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200, upload-time = "2025-04-23T18:31:13.536Z" },
+ { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890, upload-time = "2025-04-23T18:31:15.011Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359, upload-time = "2025-04-23T18:31:16.393Z" },
+ { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883, upload-time = "2025-04-23T18:31:17.892Z" },
+ { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074, upload-time = "2025-04-23T18:31:19.205Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538, upload-time = "2025-04-23T18:31:20.541Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909, upload-time = "2025-04-23T18:31:22.371Z" },
+ { url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786, upload-time = "2025-04-23T18:31:24.161Z" },
+ { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" },
+ { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" },
+ { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" },
+ { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" },
+ { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" },
+ { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" },
+ { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" },
+ { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" },
+ { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" },
+ { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" },
+ { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" },
+ { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" },
+ { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" },
+ { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" },
+ { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" },
+ { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" },
+ { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" },
+ { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" },
+ { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" },
+ { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" },
+ { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" },
+ { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" },
+ { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" },
+ { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" },
+ { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" },
+ { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" },
+ { url = "https://files.pythonhosted.org/packages/53/ea/bbe9095cdd771987d13c82d104a9c8559ae9aec1e29f139e286fd2e9256e/pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d", size = 2028677, upload-time = "2025-04-23T18:32:27.227Z" },
+ { url = "https://files.pythonhosted.org/packages/49/1d/4ac5ed228078737d457a609013e8f7edc64adc37b91d619ea965758369e5/pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954", size = 1864735, upload-time = "2025-04-23T18:32:29.019Z" },
+ { url = "https://files.pythonhosted.org/packages/23/9a/2e70d6388d7cda488ae38f57bc2f7b03ee442fbcf0d75d848304ac7e405b/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb", size = 1898467, upload-time = "2025-04-23T18:32:31.119Z" },
+ { url = "https://files.pythonhosted.org/packages/ff/2e/1568934feb43370c1ffb78a77f0baaa5a8b6897513e7a91051af707ffdc4/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7", size = 1983041, upload-time = "2025-04-23T18:32:33.655Z" },
+ { url = "https://files.pythonhosted.org/packages/01/1a/1a1118f38ab64eac2f6269eb8c120ab915be30e387bb561e3af904b12499/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4", size = 2136503, upload-time = "2025-04-23T18:32:35.519Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/da/44754d1d7ae0f22d6d3ce6c6b1486fc07ac2c524ed8f6eca636e2e1ee49b/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b", size = 2736079, upload-time = "2025-04-23T18:32:37.659Z" },
+ { url = "https://files.pythonhosted.org/packages/4d/98/f43cd89172220ec5aa86654967b22d862146bc4d736b1350b4c41e7c9c03/pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3", size = 2006508, upload-time = "2025-04-23T18:32:39.637Z" },
+ { url = "https://files.pythonhosted.org/packages/2b/cc/f77e8e242171d2158309f830f7d5d07e0531b756106f36bc18712dc439df/pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a", size = 2113693, upload-time = "2025-04-23T18:32:41.818Z" },
+ { url = "https://files.pythonhosted.org/packages/54/7a/7be6a7bd43e0a47c147ba7fbf124fe8aaf1200bc587da925509641113b2d/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782", size = 2074224, upload-time = "2025-04-23T18:32:44.033Z" },
+ { url = "https://files.pythonhosted.org/packages/2a/07/31cf8fadffbb03be1cb520850e00a8490c0927ec456e8293cafda0726184/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9", size = 2245403, upload-time = "2025-04-23T18:32:45.836Z" },
+ { url = "https://files.pythonhosted.org/packages/b6/8d/bbaf4c6721b668d44f01861f297eb01c9b35f612f6b8e14173cb204e6240/pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e", size = 2242331, upload-time = "2025-04-23T18:32:47.618Z" },
+ { url = "https://files.pythonhosted.org/packages/bb/93/3cc157026bca8f5006250e74515119fcaa6d6858aceee8f67ab6dc548c16/pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9", size = 1910571, upload-time = "2025-04-23T18:32:49.401Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/90/7edc3b2a0d9f0dda8806c04e511a67b0b7a41d2187e2003673a996fb4310/pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3", size = 1956504, upload-time = "2025-04-23T18:32:51.287Z" },
+ { url = "https://files.pythonhosted.org/packages/30/68/373d55e58b7e83ce371691f6eaa7175e3a24b956c44628eb25d7da007917/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa", size = 2023982, upload-time = "2025-04-23T18:32:53.14Z" },
+ { url = "https://files.pythonhosted.org/packages/a4/16/145f54ac08c96a63d8ed6442f9dec17b2773d19920b627b18d4f10a061ea/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29", size = 1858412, upload-time = "2025-04-23T18:32:55.52Z" },
+ { url = "https://files.pythonhosted.org/packages/41/b1/c6dc6c3e2de4516c0bb2c46f6a373b91b5660312342a0cf5826e38ad82fa/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d", size = 1892749, upload-time = "2025-04-23T18:32:57.546Z" },
+ { url = "https://files.pythonhosted.org/packages/12/73/8cd57e20afba760b21b742106f9dbdfa6697f1570b189c7457a1af4cd8a0/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e", size = 2067527, upload-time = "2025-04-23T18:32:59.771Z" },
+ { url = "https://files.pythonhosted.org/packages/e3/d5/0bb5d988cc019b3cba4a78f2d4b3854427fc47ee8ec8e9eaabf787da239c/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c", size = 2108225, upload-time = "2025-04-23T18:33:04.51Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/c5/00c02d1571913d496aabf146106ad8239dc132485ee22efe08085084ff7c/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec", size = 2069490, upload-time = "2025-04-23T18:33:06.391Z" },
+ { url = "https://files.pythonhosted.org/packages/22/a8/dccc38768274d3ed3a59b5d06f59ccb845778687652daa71df0cab4040d7/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052", size = 2237525, upload-time = "2025-04-23T18:33:08.44Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/e7/4f98c0b125dda7cf7ccd14ba936218397b44f50a56dd8c16a3091df116c3/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c", size = 2238446, upload-time = "2025-04-23T18:33:10.313Z" },
+ { url = "https://files.pythonhosted.org/packages/ce/91/2ec36480fdb0b783cd9ef6795753c1dea13882f2e68e73bce76ae8c21e6a/pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808", size = 2066678, upload-time = "2025-04-23T18:33:12.224Z" },
+ { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200, upload-time = "2025-04-23T18:33:14.199Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123, upload-time = "2025-04-23T18:33:16.555Z" },
+ { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" },
+ { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484, upload-time = "2025-04-23T18:33:20.475Z" },
+ { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896, upload-time = "2025-04-23T18:33:22.501Z" },
+ { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475, upload-time = "2025-04-23T18:33:24.528Z" },
+ { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" },
+ { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" },
+ { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757, upload-time = "2025-04-23T18:33:30.645Z" },
+ { url = "https://files.pythonhosted.org/packages/08/98/dbf3fdfabaf81cda5622154fda78ea9965ac467e3239078e0dcd6df159e7/pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101", size = 2024034, upload-time = "2025-04-23T18:33:32.843Z" },
+ { url = "https://files.pythonhosted.org/packages/8d/99/7810aa9256e7f2ccd492590f86b79d370df1e9292f1f80b000b6a75bd2fb/pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64", size = 1858578, upload-time = "2025-04-23T18:33:34.912Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/60/bc06fa9027c7006cc6dd21e48dbf39076dc39d9abbaf718a1604973a9670/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d", size = 1892858, upload-time = "2025-04-23T18:33:36.933Z" },
+ { url = "https://files.pythonhosted.org/packages/f2/40/9d03997d9518816c68b4dfccb88969756b9146031b61cd37f781c74c9b6a/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535", size = 2068498, upload-time = "2025-04-23T18:33:38.997Z" },
+ { url = "https://files.pythonhosted.org/packages/d8/62/d490198d05d2d86672dc269f52579cad7261ced64c2df213d5c16e0aecb1/pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d", size = 2108428, upload-time = "2025-04-23T18:33:41.18Z" },
+ { url = "https://files.pythonhosted.org/packages/9a/ec/4cd215534fd10b8549015f12ea650a1a973da20ce46430b68fc3185573e8/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6", size = 2069854, upload-time = "2025-04-23T18:33:43.446Z" },
+ { url = "https://files.pythonhosted.org/packages/1a/1a/abbd63d47e1d9b0d632fee6bb15785d0889c8a6e0a6c3b5a8e28ac1ec5d2/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca", size = 2237859, upload-time = "2025-04-23T18:33:45.56Z" },
+ { url = "https://files.pythonhosted.org/packages/80/1c/fa883643429908b1c90598fd2642af8839efd1d835b65af1f75fba4d94fe/pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039", size = 2239059, upload-time = "2025-04-23T18:33:47.735Z" },
+ { url = "https://files.pythonhosted.org/packages/d4/29/3cade8a924a61f60ccfa10842f75eb12787e1440e2b8660ceffeb26685e7/pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27", size = 2066661, upload-time = "2025-04-23T18:33:49.995Z" },
+]
+
+[[package]]
+name = "pylint"
+version = "3.2.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "astroid" },
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "dill" },
+ { name = "isort" },
+ { name = "mccabe" },
+ { name = "platformdirs" },
+ { name = "tomli", marker = "python_full_version < '3.11'" },
+ { name = "tomlkit" },
+ { name = "typing-extensions", marker = "python_full_version < '3.10'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9a/e9/60280b14cc1012794120345ce378504cf17409e38cd88f455dc24e0ad6b5/pylint-3.2.3.tar.gz", hash = "sha256:02f6c562b215582386068d52a30f520d84fdbcf2a95fc7e855b816060d048b60", size = 1506739, upload-time = "2024-06-06T14:19:17.955Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/50/d3/d346f779cbc9384d8b805a7557b5f2b8ee9f842bffebec9fc6364d6ae183/pylint-3.2.3-py3-none-any.whl", hash = "sha256:b3d7d2708a3e04b4679e02d99e72329a8b7ee8afb8d04110682278781f889fa8", size = 519244, upload-time = "2024-06-06T14:19:13.228Z" },
+]
+
+[[package]]
+name = "que-media"
+version = "0.1.0"
+source = { editable = "." }
+dependencies = [
+ { name = "httpcore" },
+ { name = "httpx" },
+ { name = "pydantic" },
+]
+
+[package.dev-dependencies]
+dev = [
+ { name = "mypy" },
+ { name = "pylint" },
+]
+
+[package.metadata]
+requires-dist = [
+ { name = "httpcore", specifier = ">=1.0.9" },
+ { name = "httpx", specifier = ">=0.28.1" },
+ { name = "pydantic", specifier = ">=2.11.2" },
+]
+
+[package.metadata.requires-dev]
+dev = [
+ { name = "mypy", specifier = "==1.15.0" },
+ { name = "pylint", specifier = "==3.2.3" },
+]
+
+[[package]]
+name = "sniffio"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
+]
+
+[[package]]
+name = "tomli"
+version = "2.2.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429, upload-time = "2024-11-27T22:37:56.698Z" },
+ { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067, upload-time = "2024-11-27T22:37:57.63Z" },
+ { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030, upload-time = "2024-11-27T22:37:59.344Z" },
+ { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898, upload-time = "2024-11-27T22:38:00.429Z" },
+ { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894, upload-time = "2024-11-27T22:38:02.094Z" },
+ { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319, upload-time = "2024-11-27T22:38:03.206Z" },
+ { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273, upload-time = "2024-11-27T22:38:04.217Z" },
+ { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310, upload-time = "2024-11-27T22:38:05.908Z" },
+ { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309, upload-time = "2024-11-27T22:38:06.812Z" },
+ { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762, upload-time = "2024-11-27T22:38:07.731Z" },
+ { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453, upload-time = "2024-11-27T22:38:09.384Z" },
+ { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486, upload-time = "2024-11-27T22:38:10.329Z" },
+ { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349, upload-time = "2024-11-27T22:38:11.443Z" },
+ { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159, upload-time = "2024-11-27T22:38:13.099Z" },
+ { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243, upload-time = "2024-11-27T22:38:14.766Z" },
+ { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645, upload-time = "2024-11-27T22:38:15.843Z" },
+ { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584, upload-time = "2024-11-27T22:38:17.645Z" },
+ { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875, upload-time = "2024-11-27T22:38:19.159Z" },
+ { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418, upload-time = "2024-11-27T22:38:20.064Z" },
+ { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708, upload-time = "2024-11-27T22:38:21.659Z" },
+ { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582, upload-time = "2024-11-27T22:38:22.693Z" },
+ { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543, upload-time = "2024-11-27T22:38:24.367Z" },
+ { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691, upload-time = "2024-11-27T22:38:26.081Z" },
+ { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170, upload-time = "2024-11-27T22:38:27.921Z" },
+ { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530, upload-time = "2024-11-27T22:38:29.591Z" },
+ { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666, upload-time = "2024-11-27T22:38:30.639Z" },
+ { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954, upload-time = "2024-11-27T22:38:31.702Z" },
+ { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724, upload-time = "2024-11-27T22:38:32.837Z" },
+ { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383, upload-time = "2024-11-27T22:38:34.455Z" },
+ { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" },
+]
+
+[[package]]
+name = "tomlkit"
+version = "0.13.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" },
+]
+
+[[package]]
+name = "typing-extensions"
+version = "4.15.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
+]
+
+[[package]]
+name = "typing-inspection"
+version = "0.4.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" },
+]