diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index 5a41f281..51261738 100644 --- a/.speakeasy/workflow.lock +++ b/.speakeasy/workflow.lock @@ -1,12 +1,11 @@ -speakeasyVersion: 1.608.0 +speakeasyVersion: 1.609.0 sources: Outpost API: sourceNamespace: outpost-api - sourceRevisionDigest: sha256:4042dbef541e06289b580460ccfb39d8f444c852e134de2245b13e1ffd43dcf3 - sourceBlobDigest: sha256:3859f29c380e176f9382eb969cefbb9c8701875d4837ee8a9549b78bf92eebc6 + sourceRevisionDigest: sha256:e09cf02de047cf6d007545274c477e2a90c561074b9de170d844d9ab9ffbbca6 + sourceBlobDigest: sha256:c405cfc4f2de092323a9dd68a09f7c08b563d363bce7463fc8b426d10acacf99 tags: - latest - - speakeasy-sdk-regen-1756910957 - 0.0.1 targets: outpost-go: @@ -19,10 +18,10 @@ targets: outpost-python: source: Outpost API sourceNamespace: outpost-api - sourceRevisionDigest: sha256:837897b6e2774d7ba547d9616639367bfce651d53d84190c3ee0cd32cee7e8b1 - sourceBlobDigest: sha256:3b1cd63370e0cf368a2049eaa26c9f94cd94a929de42592f8488adb5a6a3f182 + sourceRevisionDigest: sha256:e09cf02de047cf6d007545274c477e2a90c561074b9de170d844d9ab9ffbbca6 + sourceBlobDigest: sha256:c405cfc4f2de092323a9dd68a09f7c08b563d363bce7463fc8b426d10acacf99 codeSamplesNamespace: outpost-api-python-code-samples - codeSamplesRevisionDigest: sha256:c28bb1c6bd595fb3b1353dc6cdc672fa0f11c518f0bf85dcc12c5c02ad35fcc3 + codeSamplesRevisionDigest: sha256:d8540bce24dc0cc34650c9546892f1d45db9fe1867c18571e046e9c72123a246 outpost-ts: source: Outpost API sourceNamespace: outpost-api @@ -40,6 +39,7 @@ workflow: overlays: - location: ./sdks/schemas/speakeasy-modifications-overlay.yaml - location: ./sdks/schemas/error-types.yaml + - location: ./sdks/schemas/pagination-fixes-overlay.yaml registry: location: registry.speakeasyapi.dev/hookdeck-dev/outpost/outpost-api targets: diff --git a/.speakeasy/workflow.yaml b/.speakeasy/workflow.yaml index 80fed0d7..ce0988cc 100644 --- a/.speakeasy/workflow.yaml +++ b/.speakeasy/workflow.yaml @@ -7,6 +7,7 @@ sources: overlays: - location: ./sdks/schemas/speakeasy-modifications-overlay.yaml - location: ./sdks/schemas/error-types.yaml + - location: ./sdks/schemas/pagination-fixes-overlay.yaml registry: location: registry.speakeasyapi.dev/hookdeck-dev/outpost/outpost-api targets: diff --git a/sdks/outpost-python/.speakeasy/gen.lock b/sdks/outpost-python/.speakeasy/gen.lock index 58b6ee48..1830a101 100644 --- a/sdks/outpost-python/.speakeasy/gen.lock +++ b/sdks/outpost-python/.speakeasy/gen.lock @@ -1,12 +1,12 @@ lockVersion: 2.0.0 id: da774284-22d9-4b6c-bb26-1c3fc9f2c7ee management: - docChecksum: 3d3f028a2fdd56804d9ae8a2d95a414b + docChecksum: f88900fa0dfdee97044181ff0fbb5027 docVersion: 0.0.1 - speakeasyVersion: 1.594.0 - generationVersion: 2.670.1 - releaseVersion: 0.3.0 - configChecksum: 3b13091ed8addea8fde7b0db3bd41f0b + speakeasyVersion: 1.609.0 + generationVersion: 2.692.0 + releaseVersion: 0.4.0 + configChecksum: 5010174e527b0e15ea785476055a0d53 repoURL: https://github.com/hookdeck/outpost.git repoSubDirectory: sdks/outpost-python installationURL: https://github.com/hookdeck/outpost.git#subdirectory=sdks/outpost-python @@ -15,7 +15,8 @@ features: python: additionalDependencies: 1.0.0 additionalProperties: 1.0.1 - core: 5.19.5 + constsAndDefaults: 1.0.5 + core: 5.20.3 defaultEnabledRetries: 0.2.0 enumUnions: 0.1.0 envVarSecurityUsage: 0.3.2 @@ -28,6 +29,7 @@ features: methodArguments: 1.0.2 nameOverrides: 3.0.1 nullables: 1.0.1 + pagination: 3.0.5 responseFormat: 1.0.1 retries: 3.0.2 sdkHooks: 1.1.0 @@ -44,6 +46,8 @@ generatedFiles: - docs/errors/unauthorizederror.md - docs/models/awskinesisconfig.md - docs/models/awskinesiscredentials.md + - docs/models/awss3config.md + - docs/models/awss3credentials.md - docs/models/awssqsconfig.md - docs/models/awssqscredentials.md - docs/models/azureservicebusconfig.md @@ -58,6 +62,8 @@ generatedFiles: - docs/models/destination.md - docs/models/destinationawskinesis.md - docs/models/destinationawskinesistype.md + - docs/models/destinationawss3.md + - docs/models/destinationawss3type.md - docs/models/destinationawssqs.md - docs/models/destinationawssqstype.md - docs/models/destinationazureservicebus.md @@ -65,6 +71,8 @@ generatedFiles: - docs/models/destinationcreate.md - docs/models/destinationcreateawskinesis.md - docs/models/destinationcreateawskinesistype.md + - docs/models/destinationcreateawss3.md + - docs/models/destinationcreateawss3type.md - docs/models/destinationcreateawssqs.md - docs/models/destinationcreateawssqstype.md - docs/models/destinationcreateazureservicebus.md @@ -85,6 +93,7 @@ generatedFiles: - docs/models/destinationtypeschema.md - docs/models/destinationupdate.md - docs/models/destinationupdateawskinesis.md + - docs/models/destinationupdateawss3.md - docs/models/destinationupdateawssqs.md - docs/models/destinationupdatehookdeck.md - docs/models/destinationupdaterabbitmq.md @@ -126,9 +135,13 @@ generatedFiles: - docs/models/listtenanteventdeliveriesrequest.md - docs/models/listtenanteventsbydestinationglobals.md - docs/models/listtenanteventsbydestinationrequest.md + - docs/models/listtenanteventsbydestinationresponse.md + - docs/models/listtenanteventsbydestinationresponsebody.md - docs/models/listtenanteventsbydestinationstatus.md - docs/models/listtenanteventsglobals.md - docs/models/listtenanteventsrequest.md + - docs/models/listtenanteventsresponse.md + - docs/models/listtenanteventsresponsebody.md - docs/models/listtenanteventsstatus.md - docs/models/listtenanttopicsglobals.md - docs/models/listtenanttopicsrequest.md @@ -196,6 +209,8 @@ generatedFiles: - src/outpost_sdk/models/__init__.py - src/outpost_sdk/models/awskinesisconfig.py - src/outpost_sdk/models/awskinesiscredentials.py + - src/outpost_sdk/models/awss3config.py + - src/outpost_sdk/models/awss3credentials.py - src/outpost_sdk/models/awssqsconfig.py - src/outpost_sdk/models/awssqscredentials.py - src/outpost_sdk/models/azureservicebusconfig.py @@ -206,10 +221,12 @@ generatedFiles: - src/outpost_sdk/models/deliveryattempt.py - src/outpost_sdk/models/destination.py - src/outpost_sdk/models/destinationawskinesis.py + - src/outpost_sdk/models/destinationawss3.py - src/outpost_sdk/models/destinationawssqs.py - src/outpost_sdk/models/destinationazureservicebus.py - src/outpost_sdk/models/destinationcreate.py - src/outpost_sdk/models/destinationcreateawskinesis.py + - src/outpost_sdk/models/destinationcreateawss3.py - src/outpost_sdk/models/destinationcreateawssqs.py - src/outpost_sdk/models/destinationcreateazureservicebus.py - src/outpost_sdk/models/destinationcreatehookdeck.py @@ -221,6 +238,7 @@ generatedFiles: - src/outpost_sdk/models/destinationtypeschema.py - src/outpost_sdk/models/destinationupdate.py - src/outpost_sdk/models/destinationupdateawskinesis.py + - src/outpost_sdk/models/destinationupdateawss3.py - src/outpost_sdk/models/destinationupdateawssqs.py - src/outpost_sdk/models/destinationupdatehookdeck.py - src/outpost_sdk/models/destinationupdaterabbitmq.py @@ -363,7 +381,7 @@ examples: query: {} responses: "200": - application/json: [{"id": "des_webhook_123", "type": "webhook", "topics": ["user.created", "order.shipped"], "disabled_at": null, "created_at": "2024-02-15T10:00:00Z", "config": {"url": "https://my-service.com/webhook/handler"}, "credentials": {"secret": "whsec_abc123def456", "previous_secret": "whsec_prev789xyz012", "previous_secret_invalid_at": "2024-02-16T10:00:00Z"}}, {"id": "des_sqs_456", "type": "aws_sqs", "topics": ["*"], "disabled_at": "2024-03-01T12:00:00Z", "created_at": "2024-02-20T11:30:00Z", "config": {"endpoint": "https://sqs.us-west-2.amazonaws.com", "queue_url": "https://sqs.us-west-2.amazonaws.com/123456789012/my-app-queue"}, "credentials": {"key": "AKIAIOSFODNN7EXAMPLE", "secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}}] + application/json: [{"id": "des_webhook_123", "type": "webhook", "topics": ["user.created", "order.shipped"], "disabled_at": null, "created_at": "2024-02-15T10:00:00Z", "config": {"url": "https://my-service.com/webhook/handler"}, "credentials": {"secret": "whsec_abc123def456", "previous_secret": "whsec_prev789xyz012", "previous_secret_invalid_at": "2024-02-16T10:00:00Z"}}, {"id": "des_sqs_456", "type": "aws_sqs", "topics": ["*"], "disabled_at": "2024-03-01T12:00:00Z", "created_at": "2024-02-20T11:30:00Z", "config": {"endpoint": "https://sqs.us-west-2.amazonaws.com", "queue_url": "https://sqs.us-west-2.amazonaws.com/123456789012/my-app-queue"}, "credentials": {"key": "AKIAIOSFODNN7EXAMPLE", "secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}}, {"id": "des_s3_789", "type": "aws_s3", "topics": ["*"], "disabled_at": null, "created_at": "2024-03-20T12:00:00Z", "config": {"bucket": "my-bucket", "region": "us-east-1"}, "credentials": {"key": "AKIAIOSFODNN7EXAMPLE", "secret": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"}}] createTenantDestination: WebhookCreatedExample: parameters: @@ -455,7 +473,7 @@ examples: tenant_id: "" responses: "200": - application/json: [{"type": "webhook", "label": "Webhook", "description": "Send event via an HTTP POST request to a URL", "icon": "", "instructions": "Enter the URL...", "config_fields": [{"type": "text", "label": "URL", "description": "The URL to send the webhook to.", "required": true, "pattern": "^https?://.*"}], "credential_fields": [{"type": "text", "label": "Secret", "description": "Optional signing secret.", "required": false, "sensitive": true}]}, {"type": "aws_sqs", "label": "AWS SQS", "description": "Send event to an AWS SQS queue", "icon": "", "instructions": "Enter Queue URL...", "config_fields": [{"type": "text", "label": "Queue URL", "description": "The URL of the SQS queue.", "required": true}, {"type": "text", "label": "Endpoint", "description": "Optional custom AWS endpoint URL.", "required": false}], "credential_fields": [{"type": "text", "label": "Key", "description": "AWS Access Key ID.", "required": true, "sensitive": true}, {"type": "text", "label": "Secret", "description": "AWS Secret Access Key.", "required": true, "sensitive": true}, {"type": "text", "label": "Session", "description": "Optional AWS Session Token.", "required": false, "sensitive": true}]}] + application/json: [{"type": "webhook", "label": "Webhook", "description": "Send event via an HTTP POST request to a URL", "icon": "", "instructions": "Enter the URL...", "config_fields": [{"type": "text", "label": "URL", "description": "The URL to send the webhook to.", "required": true, "pattern": "^https?://.*"}], "credential_fields": [{"type": "text", "label": "Secret", "description": "Optional signing secret.", "required": false, "sensitive": true}]}, {"type": "aws_sqs", "label": "AWS SQS", "description": "Send event to an AWS SQS queue", "icon": "", "instructions": "Enter Queue URL...", "config_fields": [{"type": "text", "label": "Queue URL", "description": "The URL of the SQS queue.", "required": true}, {"type": "text", "label": "Endpoint", "description": "Optional custom AWS endpoint URL.", "required": false}], "credential_fields": [{"type": "text", "label": "Key", "description": "AWS Access Key ID.", "required": true, "sensitive": true}, {"type": "text", "label": "Secret", "description": "AWS Secret Access Key.", "required": true, "sensitive": true}, {"type": "text", "label": "Session", "description": "Optional AWS Session Token.", "required": false, "sensitive": true}]}, {"type": "aws_s3", "label": "AWS S3", "description": "Store events in an Amazon S3 bucket", "icon": "", "instructions": "Enter bucket and region...", "config_fields": [{"type": "text", "label": "Bucket Name", "description": "The name of the S3 bucket.", "required": true}, {"type": "text", "label": "AWS Region", "description": "The AWS region where the bucket is located.", "required": true}], "credential_fields": [{"type": "text", "label": "Key", "description": "AWS Access Key ID.", "required": true, "sensitive": true}, {"type": "text", "label": "Secret", "description": "AWS Secret Access Key.", "required": true, "sensitive": true}]}, {"type": "aws_s3", "label": "AWS S3", "description": "Store events in an Amazon S3 bucket", "icon": "", "instructions": "Enter bucket and region...", "config_fields": [{"type": "text", "label": "Bucket Name", "description": "The name of the S3 bucket.", "required": true}, {"type": "text", "label": "AWS Region", "description": "The AWS region where the bucket is located.", "required": true}], "credential_fields": [{"type": "text", "label": "Key", "description": "AWS Access Key ID.", "required": true, "sensitive": true}, {"type": "text", "label": "Secret", "description": "AWS Secret Access Key.", "required": true, "sensitive": true}]}] getTenantDestinationTypeSchema: WebhookSchemaExample: parameters: @@ -496,10 +514,11 @@ examples: parameters: path: tenant_id: "" - query: {} + query: + limit: 100 responses: "200": - application/json: [{"id": "evt_123", "destination_id": "des_456", "topic": "user.created", "time": "2024-01-01T00:00:00Z", "successful_at": "2024-01-01T00:00:05Z", "metadata": {"source": "crm"}, "data": {"user_id": "userid", "status": "active"}}, {"id": "evt_789", "destination_id": "des_456", "topic": "order.shipped", "time": "2024-01-02T10:00:00Z", "successful_at": null, "metadata": {"source": "oms"}, "data": {"order_id": "orderid", "tracking": "1Z..."}}] + application/json: {"count": 2, "data": [{"id": "evt_123", "destination_id": "des_456", "topic": "user.created", "time": "2024-01-01T00:00:00Z", "successful_at": "2024-01-01T00:00:05Z", "metadata": {"source": "crm"}, "data": {"user_id": "userid", "status": "active"}}, {"id": "evt_789", "destination_id": "des_456", "topic": "order.shipped", "time": "2024-01-02T10:00:00Z", "successful_at": null, "metadata": {"source": "oms"}, "data": {"order_id": "orderid", "tracking": "1Z..."}}], "next": "", "prev": ""} getTenantEvent: EventExample: parameters: @@ -524,10 +543,11 @@ examples: path: tenant_id: "" destination_id: "" - query: {} + query: + limit: 100 responses: "200": - application/json: [{"id": "evt_123", "destination_id": "des_456", "topic": "user.created", "time": "2024-01-01T00:00:00Z", "successful_at": "2024-01-01T00:00:05Z", "metadata": {"source": "crm"}, "data": {"user_id": "userid", "status": "active"}}, {"id": "evt_789", "destination_id": "des_456", "topic": "order.shipped", "time": "2024-01-02T10:00:00Z", "successful_at": null, "metadata": {"source": "oms"}, "data": {"order_id": "orderid", "tracking": "1Z..."}}] + application/json: {"count": 2, "data": [{"id": "evt_123", "destination_id": "des_456", "topic": "user.created", "time": "2024-01-01T00:00:00Z", "successful_at": "2024-01-01T00:00:05Z", "metadata": {"source": "crm"}, "data": {"user_id": "userid", "status": "active"}}, {"id": "evt_789", "destination_id": "des_456", "topic": "order.shipped", "time": "2024-01-02T10:00:00Z", "successful_at": null, "metadata": {"source": "oms"}, "data": {"order_id": "orderid", "tracking": "1Z..."}}], "next": "", "prev": ""} getTenantEventByDestination: EventExample: parameters: diff --git a/sdks/outpost-python/.speakeasy/gen.yaml b/sdks/outpost-python/.speakeasy/gen.yaml index 4747d2a7..9420210b 100644 --- a/sdks/outpost-python/.speakeasy/gen.yaml +++ b/sdks/outpost-python/.speakeasy/gen.yaml @@ -21,10 +21,13 @@ generation: generateNewTests: false skipResponseBodyAssertions: false python: - version: 0.3.0 + version: 0.4.0 additionalDependencies: dev: {} main: {} + allowedRedefinedBuiltins: + - id + - object authors: - Speakeasy baseErrorName: OutpostError @@ -51,6 +54,7 @@ python: methodArguments: infer-optional-args moduleName: "" outputModelSuffix: output + packageManager: poetry packageName: outpost_sdk pytestFilterWarnings: [] pytestTimeout: 0 diff --git a/sdks/outpost-python/README.md b/sdks/outpost-python/README.md index fee4539c..5a99baad 100644 --- a/sdks/outpost-python/README.md +++ b/sdks/outpost-python/README.md @@ -25,6 +25,7 @@ Outpost API: The Outpost API is a REST-based JSON API for managing tenants, dest * [Authentication](#authentication) * [Available Resources and Operations](#available-resources-and-operations) * [Global Parameters](#global-parameters) + * [Pagination](#pagination) * [Retries](#retries) * [Error Handling](#error-handling) * [Server Selection](#server-selection) @@ -45,7 +46,15 @@ Outpost API: The Outpost API is a REST-based JSON API for managing tenants, dest > > 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 either *pip* or *poetry* package managers. +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 outpost_sdk +``` ### PIP @@ -125,7 +134,7 @@ with Outpost() as outpost:
-The same SDK client can also be used to make asychronous requests by importing asyncio. +The same SDK client can also be used to make asynchronous requests by importing asyncio. ```python # Asynchronous Example import asyncio @@ -269,6 +278,35 @@ with Outpost( ``` + +## Pagination + +Some of the endpoints in this SDK support pagination. To use pagination, you make your SDK calls as usual, but the +returned response object will have a `Next` method that can be called to pull down the next group of results. If the +return value of `Next` is `None`, then there are no more pages to be fetched. + +Here's an example of one such pagination call: +```python +from outpost_sdk import Outpost, models + + +with Outpost( + tenant_id="", + security=models.Security( + admin_api_key="", + ), +) as outpost: + + res = outpost.events.list(limit=100) + + while res is not None: + # Handle items + + res = res.next() + +``` + + ## Retries diff --git a/sdks/outpost-python/USAGE.md b/sdks/outpost-python/USAGE.md index 63e915db..a8d3a7d3 100644 --- a/sdks/outpost-python/USAGE.md +++ b/sdks/outpost-python/USAGE.md @@ -14,7 +14,7 @@ with Outpost() as outpost:
-The same SDK client can also be used to make asychronous requests by importing asyncio. +The same SDK client can also be used to make asynchronous requests by importing asyncio. ```python # Asynchronous Example import asyncio diff --git a/sdks/outpost-python/docs/models/awss3config.md b/sdks/outpost-python/docs/models/awss3config.md new file mode 100644 index 00000000..8171dda6 --- /dev/null +++ b/sdks/outpost-python/docs/models/awss3config.md @@ -0,0 +1,11 @@ +# Awss3Config + + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| `bucket` | *str* | :heavy_check_mark: | The name of your AWS S3 bucket. | my-bucket | +| `region` | *str* | :heavy_check_mark: | The AWS region where your bucket is located. | us-east-1 | +| `key_template` | *Optional[str]* | :heavy_minus_sign: | JMESPath expression for generating S3 object keys. Default is join('', [time.rfc3339_nano, '_', metadata."event-id", '.json']). | join('/', [time.year, time.month, time.day, metadata.`"event-id"`, '.json']) | +| `storage_class` | *Optional[str]* | :heavy_minus_sign: | The storage class for the S3 objects (e.g., STANDARD, INTELLIGENT_TIERING, GLACIER, etc.). Defaults to "STANDARD". | STANDARD | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/awss3credentials.md b/sdks/outpost-python/docs/models/awss3credentials.md new file mode 100644 index 00000000..37ed6416 --- /dev/null +++ b/sdks/outpost-python/docs/models/awss3credentials.md @@ -0,0 +1,10 @@ +# Awss3Credentials + + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------- | +| `key` | *str* | :heavy_check_mark: | AWS Access Key ID. | AKIAIOSFODNN7EXAMPLE | +| `secret` | *str* | :heavy_check_mark: | AWS Secret Access Key. | wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY | +| `session` | *Optional[str]* | :heavy_minus_sign: | Optional AWS Session Token (for temporary credentials). | AQoDYXdzEPT//////////wEXAMPLE... | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/destination.md b/sdks/outpost-python/docs/models/destination.md index ec69fcc0..b14d840f 100644 --- a/sdks/outpost-python/docs/models/destination.md +++ b/sdks/outpost-python/docs/models/destination.md @@ -39,3 +39,9 @@ value: models.DestinationAWSKinesis = /* values here */ value: models.DestinationAzureServiceBus = /* values here */ ``` +### `models.DestinationAwss3` + +```python +value: models.DestinationAwss3 = /* values here */ +``` + diff --git a/sdks/outpost-python/docs/models/destinationawss3.md b/sdks/outpost-python/docs/models/destinationawss3.md new file mode 100644 index 00000000..e1f7a55a --- /dev/null +++ b/sdks/outpost-python/docs/models/destinationawss3.md @@ -0,0 +1,16 @@ +# DestinationAwss3 + + +## Fields + +| Field | Type | Required | Description | Example | +| ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | +| `id` | *str* | :heavy_check_mark: | Control plane generated ID or user provided ID for the destination. | des_12345 | +| `type` | [models.DestinationAwss3Type](../models/destinationawss3type.md) | :heavy_check_mark: | Type of the destination. | aws_s3 | +| `topics` | [models.TopicsUnion](../models/topicsunion.md) | :heavy_check_mark: | "*" or an array of enabled topics. | * | +| `disabled_at` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_check_mark: | ISO Date when the destination was disabled, or null if enabled. | | +| `created_at` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_check_mark: | ISO Date when the destination was created. | 2024-01-01T00:00:00Z | +| `config` | [models.Awss3Config](../models/awss3config.md) | :heavy_check_mark: | N/A | | +| `credentials` | [models.Awss3Credentials](../models/awss3credentials.md) | :heavy_check_mark: | N/A | | +| `target` | *Optional[str]* | :heavy_minus_sign: | A human-readable representation of the destination target (bucket and region). Read-only. | my-bucket in us-east-1 | +| `target_url` | *OptionalNullable[str]* | :heavy_minus_sign: | A URL link to the destination target (AWS Console link to the bucket). Read-only. | | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/destinationawss3type.md b/sdks/outpost-python/docs/models/destinationawss3type.md new file mode 100644 index 00000000..dca9825f --- /dev/null +++ b/sdks/outpost-python/docs/models/destinationawss3type.md @@ -0,0 +1,10 @@ +# DestinationAwss3Type + +Type of the destination. + + +## Values + +| Name | Value | +| -------- | -------- | +| `AWS_S3` | aws_s3 | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/destinationcreate.md b/sdks/outpost-python/docs/models/destinationcreate.md index 747b2107..6bc13818 100644 --- a/sdks/outpost-python/docs/models/destinationcreate.md +++ b/sdks/outpost-python/docs/models/destinationcreate.md @@ -39,3 +39,9 @@ value: models.DestinationCreateAWSKinesis = /* values here */ value: models.DestinationCreateAzureServiceBus = /* values here */ ``` +### `models.DestinationCreateAwss3` + +```python +value: models.DestinationCreateAwss3 = /* values here */ +``` + diff --git a/sdks/outpost-python/docs/models/destinationcreateawss3.md b/sdks/outpost-python/docs/models/destinationcreateawss3.md new file mode 100644 index 00000000..2ce1e6b7 --- /dev/null +++ b/sdks/outpost-python/docs/models/destinationcreateawss3.md @@ -0,0 +1,12 @@ +# DestinationCreateAwss3 + + +## Fields + +| Field | Type | Required | Description | Example | +| ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | +| `id` | *Optional[str]* | :heavy_minus_sign: | Optional user-provided ID. A UUID will be generated if empty. | user-provided-id | +| `type` | [models.DestinationCreateAwss3Type](../models/destinationcreateawss3type.md) | :heavy_check_mark: | Type of the destination. Must be 'aws_s3'. | | +| `topics` | [models.TopicsUnion](../models/topicsunion.md) | :heavy_check_mark: | "*" or an array of enabled topics. | * | +| `config` | [models.Awss3Config](../models/awss3config.md) | :heavy_check_mark: | N/A | | +| `credentials` | [models.Awss3Credentials](../models/awss3credentials.md) | :heavy_check_mark: | N/A | | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/destinationcreateawss3type.md b/sdks/outpost-python/docs/models/destinationcreateawss3type.md new file mode 100644 index 00000000..dbcca224 --- /dev/null +++ b/sdks/outpost-python/docs/models/destinationcreateawss3type.md @@ -0,0 +1,10 @@ +# DestinationCreateAwss3Type + +Type of the destination. Must be 'aws_s3'. + + +## Values + +| Name | Value | +| -------- | -------- | +| `AWS_S3` | aws_s3 | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/destinationupdate.md b/sdks/outpost-python/docs/models/destinationupdate.md index 5bab9bfe..b18d6ea4 100644 --- a/sdks/outpost-python/docs/models/destinationupdate.md +++ b/sdks/outpost-python/docs/models/destinationupdate.md @@ -33,3 +33,9 @@ value: models.DestinationUpdateHookdeck = /* values here */ value: models.DestinationUpdateAWSKinesis = /* values here */ ``` +### `models.DestinationUpdateAwss3` + +```python +value: models.DestinationUpdateAwss3 = /* values here */ +``` + diff --git a/sdks/outpost-python/docs/models/destinationupdateawss3.md b/sdks/outpost-python/docs/models/destinationupdateawss3.md new file mode 100644 index 00000000..78f6d9d2 --- /dev/null +++ b/sdks/outpost-python/docs/models/destinationupdateawss3.md @@ -0,0 +1,10 @@ +# DestinationUpdateAwss3 + + +## Fields + +| Field | Type | Required | Description | Example | +| ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | ------------------------------------------------------------------ | +| `topics` | [Optional[models.TopicsUnion]](../models/topicsunion.md) | :heavy_minus_sign: | "*" or an array of enabled topics. | * | +| `config` | [Optional[models.Awss3Config]](../models/awss3config.md) | :heavy_minus_sign: | N/A | | +| `credentials` | [Optional[models.Awss3Credentials]](../models/awss3credentials.md) | :heavy_minus_sign: | N/A | | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/getdestinationtypeschematype.md b/sdks/outpost-python/docs/models/getdestinationtypeschematype.md index 24b1d90b..da1ac07c 100644 --- a/sdks/outpost-python/docs/models/getdestinationtypeschematype.md +++ b/sdks/outpost-python/docs/models/getdestinationtypeschematype.md @@ -11,4 +11,5 @@ The type of the destination. | `AWS_SQS` | aws_sqs | | `RABBITMQ` | rabbitmq | | `HOOKDECK` | hookdeck | -| `AWS_KINESIS` | aws_kinesis | \ No newline at end of file +| `AWS_KINESIS` | aws_kinesis | +| `AWS_S3` | aws_s3 | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/gettenantdestinationtypeschematype.md b/sdks/outpost-python/docs/models/gettenantdestinationtypeschematype.md index 2853429f..f240006d 100644 --- a/sdks/outpost-python/docs/models/gettenantdestinationtypeschematype.md +++ b/sdks/outpost-python/docs/models/gettenantdestinationtypeschematype.md @@ -11,4 +11,5 @@ The type of the destination. | `AWS_SQS` | aws_sqs | | `RABBITMQ` | rabbitmq | | `HOOKDECK` | hookdeck | -| `AWS_KINESIS` | aws_kinesis | \ No newline at end of file +| `AWS_KINESIS` | aws_kinesis | +| `AWS_S3` | aws_s3 | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/listtenantdestinationstypeenum1.md b/sdks/outpost-python/docs/models/listtenantdestinationstypeenum1.md index 6e1b8124..c013715a 100644 --- a/sdks/outpost-python/docs/models/listtenantdestinationstypeenum1.md +++ b/sdks/outpost-python/docs/models/listtenantdestinationstypeenum1.md @@ -9,4 +9,5 @@ | `AWS_SQS` | aws_sqs | | `RABBITMQ` | rabbitmq | | `HOOKDECK` | hookdeck | -| `AWS_KINESIS` | aws_kinesis | \ No newline at end of file +| `AWS_KINESIS` | aws_kinesis | +| `AWS_S3` | aws_s3 | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/listtenantdestinationstypeenum2.md b/sdks/outpost-python/docs/models/listtenantdestinationstypeenum2.md index 678e63a5..9fa71bbc 100644 --- a/sdks/outpost-python/docs/models/listtenantdestinationstypeenum2.md +++ b/sdks/outpost-python/docs/models/listtenantdestinationstypeenum2.md @@ -9,4 +9,5 @@ | `AWS_SQS` | aws_sqs | | `RABBITMQ` | rabbitmq | | `HOOKDECK` | hookdeck | -| `AWS_KINESIS` | aws_kinesis | \ No newline at end of file +| `AWS_KINESIS` | aws_kinesis | +| `AWS_S3` | aws_s3 | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/listtenanteventsbydestinationrequest.md b/sdks/outpost-python/docs/models/listtenanteventsbydestinationrequest.md index 8ded4e5c..14277085 100644 --- a/sdks/outpost-python/docs/models/listtenanteventsbydestinationrequest.md +++ b/sdks/outpost-python/docs/models/listtenanteventsbydestinationrequest.md @@ -7,4 +7,9 @@ | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | | `tenant_id` | *Optional[str]* | :heavy_minus_sign: | The ID of the tenant. Required when using AdminApiKey authentication. | | `destination_id` | *str* | :heavy_check_mark: | The ID of the destination. | -| `status` | [Optional[models.ListTenantEventsByDestinationStatus]](../models/listtenanteventsbydestinationstatus.md) | :heavy_minus_sign: | Filter events by delivery status. | \ No newline at end of file +| `status` | [Optional[models.ListTenantEventsByDestinationStatus]](../models/listtenanteventsbydestinationstatus.md) | :heavy_minus_sign: | Filter events by delivery status. | +| `next` | *Optional[str]* | :heavy_minus_sign: | Cursor for next page of results | +| `prev` | *Optional[str]* | :heavy_minus_sign: | Cursor for previous page of results | +| `limit` | *Optional[int]* | :heavy_minus_sign: | Number of items per page (default 100, max 1000) | +| `start` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_minus_sign: | Start time filter (RFC3339 format) | +| `end` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_minus_sign: | End time filter (RFC3339 format) | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/listtenanteventsbydestinationresponse.md b/sdks/outpost-python/docs/models/listtenanteventsbydestinationresponse.md new file mode 100644 index 00000000..7aff9813 --- /dev/null +++ b/sdks/outpost-python/docs/models/listtenanteventsbydestinationresponse.md @@ -0,0 +1,8 @@ +# ListTenantEventsByDestinationResponse + + +## Fields + +| Field | Type | Required | Description | +| ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | +| `result` | [models.ListTenantEventsByDestinationResponseBody](../models/listtenanteventsbydestinationresponsebody.md) | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/listtenanteventsbydestinationresponsebody.md b/sdks/outpost-python/docs/models/listtenanteventsbydestinationresponsebody.md new file mode 100644 index 00000000..c00232ee --- /dev/null +++ b/sdks/outpost-python/docs/models/listtenanteventsbydestinationresponsebody.md @@ -0,0 +1,13 @@ +# ListTenantEventsByDestinationResponseBody + +A paginated list of events for the destination. + + +## Fields + +| Field | Type | Required | Description | Example | +| ----------------------------------------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------- | +| `count` | *int* | :heavy_check_mark: | Total number of items across all pages | 42 | +| `data` | List[[models.Event](../models/event.md)] | :heavy_check_mark: | N/A | | +| `next_cursor` | *str* | :heavy_check_mark: | Cursor for next page (empty string if no next page) | | +| `prev_cursor` | *str* | :heavy_check_mark: | Cursor for previous page (empty string if no previous page) | | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/listtenanteventsrequest.md b/sdks/outpost-python/docs/models/listtenanteventsrequest.md index bce473ea..851fe44a 100644 --- a/sdks/outpost-python/docs/models/listtenanteventsrequest.md +++ b/sdks/outpost-python/docs/models/listtenanteventsrequest.md @@ -7,4 +7,9 @@ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------ | | `tenant_id` | *Optional[str]* | :heavy_minus_sign: | The ID of the tenant. Required when using AdminApiKey authentication. | | `destination_id` | [Optional[models.DestinationID]](../models/destinationid.md) | :heavy_minus_sign: | Filter events by destination ID(s). | -| `status` | [Optional[models.ListTenantEventsStatus]](../models/listtenanteventsstatus.md) | :heavy_minus_sign: | Filter events by delivery status. | \ No newline at end of file +| `status` | [Optional[models.ListTenantEventsStatus]](../models/listtenanteventsstatus.md) | :heavy_minus_sign: | Filter events by delivery status. | +| `next` | *Optional[str]* | :heavy_minus_sign: | Cursor for next page of results | +| `prev` | *Optional[str]* | :heavy_minus_sign: | Cursor for previous page of results | +| `limit` | *Optional[int]* | :heavy_minus_sign: | Number of items per page (default 100, max 1000) | +| `start` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_minus_sign: | Start time filter (RFC3339 format) | +| `end` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_minus_sign: | End time filter (RFC3339 format) | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/listtenanteventsresponse.md b/sdks/outpost-python/docs/models/listtenanteventsresponse.md new file mode 100644 index 00000000..ac9e10f4 --- /dev/null +++ b/sdks/outpost-python/docs/models/listtenanteventsresponse.md @@ -0,0 +1,8 @@ +# ListTenantEventsResponse + + +## Fields + +| Field | Type | Required | Description | +| -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +| `result` | [models.ListTenantEventsResponseBody](../models/listtenanteventsresponsebody.md) | :heavy_check_mark: | N/A | \ No newline at end of file diff --git a/sdks/outpost-python/docs/models/listtenanteventsresponsebody.md b/sdks/outpost-python/docs/models/listtenanteventsresponsebody.md new file mode 100644 index 00000000..c2d85915 --- /dev/null +++ b/sdks/outpost-python/docs/models/listtenanteventsresponsebody.md @@ -0,0 +1,13 @@ +# ListTenantEventsResponseBody + +A paginated list of events. + + +## Fields + +| Field | Type | Required | Description | Example | +| ----------------------------------------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------- | +| `count` | *int* | :heavy_check_mark: | Total number of items across all pages | 42 | +| `data` | List[[models.Event](../models/event.md)] | :heavy_check_mark: | N/A | | +| `next_cursor` | *str* | :heavy_check_mark: | Cursor for next page (empty string if no next page) | | +| `prev_cursor` | *str* | :heavy_check_mark: | Cursor for previous page (empty string if no previous page) | | \ No newline at end of file diff --git a/sdks/outpost-python/docs/sdks/events/README.md b/sdks/outpost-python/docs/sdks/events/README.md index 0d970b34..c57f39bd 100644 --- a/sdks/outpost-python/docs/sdks/events/README.md +++ b/sdks/outpost-python/docs/sdks/events/README.md @@ -32,10 +32,12 @@ with Outpost( ), ) as outpost: - res = outpost.events.list() + res = outpost.events.list(limit=100) - # Handle response - print(res) + while res is not None: + # Handle items + + res = res.next() ``` @@ -46,11 +48,16 @@ with Outpost( | `tenant_id` | *Optional[str]* | :heavy_minus_sign: | The ID of the tenant. Required when using AdminApiKey authentication. | | `destination_id` | [Optional[models.DestinationID]](../../models/destinationid.md) | :heavy_minus_sign: | Filter events by destination ID(s). | | `status` | [Optional[models.ListTenantEventsStatus]](../../models/listtenanteventsstatus.md) | :heavy_minus_sign: | Filter events by delivery status. | +| `next` | *Optional[str]* | :heavy_minus_sign: | Cursor for next page of results | +| `prev` | *Optional[str]* | :heavy_minus_sign: | Cursor for previous page of results | +| `limit` | *Optional[int]* | :heavy_minus_sign: | Number of items per page (default 100, max 1000) | +| `start` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_minus_sign: | Start time filter (RFC3339 format) | +| `end` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_minus_sign: | End time filter (RFC3339 format) | | `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.md) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. | ### Response -**[List[models.Event]](../../models/.md)** +**[models.ListTenantEventsResponse](../../models/listtenanteventsresponse.md)** ### Errors @@ -189,10 +196,12 @@ with Outpost( ), ) as outpost: - res = outpost.events.list_by_destination(destination_id="") + res = outpost.events.list_by_destination(destination_id="", limit=100) - # Handle response - print(res) + while res is not None: + # Handle items + + res = res.next() ``` @@ -203,11 +212,16 @@ with Outpost( | `destination_id` | *str* | :heavy_check_mark: | The ID of the destination. | | `tenant_id` | *Optional[str]* | :heavy_minus_sign: | The ID of the tenant. Required when using AdminApiKey authentication. | | `status` | [Optional[models.ListTenantEventsByDestinationStatus]](../../models/listtenanteventsbydestinationstatus.md) | :heavy_minus_sign: | Filter events by delivery status. | +| `next` | *Optional[str]* | :heavy_minus_sign: | Cursor for next page of results | +| `prev` | *Optional[str]* | :heavy_minus_sign: | Cursor for previous page of results | +| `limit` | *Optional[int]* | :heavy_minus_sign: | Number of items per page (default 100, max 1000) | +| `start` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_minus_sign: | Start time filter (RFC3339 format) | +| `end` | [date](https://docs.python.org/3/library/datetime.html#date-objects) | :heavy_minus_sign: | End time filter (RFC3339 format) | | `retries` | [Optional[utils.RetryConfig]](../../models/utils/retryconfig.md) | :heavy_minus_sign: | Configuration to override the default retry behavior of the client. | ### Response -**[List[models.Event]](../../models/.md)** +**[models.ListTenantEventsByDestinationResponse](../../models/listtenanteventsbydestinationresponse.md)** ### Errors diff --git a/sdks/outpost-python/poetry.toml b/sdks/outpost-python/poetry.toml index ab1033bd..cd3492ac 100644 --- a/sdks/outpost-python/poetry.toml +++ b/sdks/outpost-python/poetry.toml @@ -1,2 +1,3 @@ + [virtualenvs] in-project = true diff --git a/sdks/outpost-python/pyproject.toml b/sdks/outpost-python/pyproject.toml index a01c3a9b..fa9ca3ff 100644 --- a/sdks/outpost-python/pyproject.toml +++ b/sdks/outpost-python/pyproject.toml @@ -1,6 +1,7 @@ + [project] name = "outpost_sdk" -version = "0.3.0" +version = "0.4.0" description = "Python Client SDK Generated by Speakeasy." authors = [{ name = "Speakeasy" },] readme = "README-PYPI.md" @@ -8,6 +9,7 @@ requires-python = ">=3.9.2" dependencies = [ "httpcore >=1.0.9", "httpx >=0.28.1", + "jsonpath-python >=1.0.6", "pydantic >=2.11.2", ] @@ -34,6 +36,7 @@ build-backend = "poetry.core.masonry.api" [tool.pytest.ini_options] asyncio_default_fixture_loop_scope = "function" +asyncio_mode = "auto" pythonpath = ["src"] [tool.mypy] diff --git a/sdks/outpost-python/scripts/prepare_readme.py b/sdks/outpost-python/scripts/prepare_readme.py index ab7814ff..2e9fa3be 100644 --- a/sdks/outpost-python/scripts/prepare_readme.py +++ b/sdks/outpost-python/scripts/prepare_readme.py @@ -10,12 +10,17 @@ GITHUB_URL = ( GITHUB_URL[: -len(".git")] if GITHUB_URL.endswith(".git") else GITHUB_URL ) + REPO_SUBDIR = "sdks/outpost-python" + # Ensure the subdirectory has a trailing slash + if not REPO_SUBDIR.endswith("/"): + 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, diff --git a/sdks/outpost-python/scripts/publish.sh b/sdks/outpost-python/scripts/publish.sh index f2f2cf2c..2a3ead70 100755 --- a/sdks/outpost-python/scripts/publish.sh +++ b/sdks/outpost-python/scripts/publish.sh @@ -1,5 +1,4 @@ #!/usr/bin/env bash - export POETRY_PYPI_TOKEN_PYPI=${PYPI_TOKEN} poetry run python scripts/prepare_readme.py diff --git a/sdks/outpost-python/src/outpost_sdk/_version.py b/sdks/outpost-python/src/outpost_sdk/_version.py index e359faa8..846f7c93 100644 --- a/sdks/outpost-python/src/outpost_sdk/_version.py +++ b/sdks/outpost-python/src/outpost_sdk/_version.py @@ -3,10 +3,10 @@ import importlib.metadata __title__: str = "outpost_sdk" -__version__: str = "0.3.0" +__version__: str = "0.4.0" __openapi_doc_version__: str = "0.0.1" -__gen_version__: str = "2.670.1" -__user_agent__: str = "speakeasy-sdk/python 0.3.0 2.670.1 0.0.1 outpost_sdk" +__gen_version__: str = "2.692.0" +__user_agent__: str = "speakeasy-sdk/python 0.4.0 2.692.0 0.0.1 outpost_sdk" try: if __package__ is not None: diff --git a/sdks/outpost-python/src/outpost_sdk/basesdk.py b/sdks/outpost-python/src/outpost_sdk/basesdk.py index 6dd9975b..d4ba700b 100644 --- a/sdks/outpost-python/src/outpost_sdk/basesdk.py +++ b/sdks/outpost-python/src/outpost_sdk/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/sdks/outpost-python/src/outpost_sdk/errors/__init__.py b/sdks/outpost-python/src/outpost_sdk/errors/__init__.py index c1ba70ff..74936d0c 100644 --- a/sdks/outpost-python/src/outpost_sdk/errors/__init__.py +++ b/sdks/outpost-python/src/outpost_sdk/errors/__init__.py @@ -1,7 +1,10 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" +from .outposterror import OutpostError from typing import TYPE_CHECKING from importlib import import_module +import builtins +import sys if TYPE_CHECKING: from .apierror import APIError @@ -9,7 +12,6 @@ from .internalservererror import InternalServerError, InternalServerErrorData from .no_response_error import NoResponseError from .notfound_error import NotFoundError, NotFoundErrorData - from .outposterror import OutpostError from .ratelimited_error import RateLimitedError, RateLimitedErrorData from .responsevalidationerror import ResponseValidationError from .timeout_error import TimeoutErrorT, TimeoutErrorTData @@ -43,7 +45,6 @@ "NoResponseError": ".no_response_error", "NotFoundError": ".notfound_error", "NotFoundErrorData": ".notfound_error", - "OutpostError": ".outposterror", "RateLimitedError": ".ratelimited_error", "RateLimitedErrorData": ".ratelimited_error", "ResponseValidationError": ".responsevalidationerror", @@ -54,6 +55,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: @@ -62,7 +75,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: @@ -76,5 +89,5 @@ def __getattr__(attr_name: str) -> object: def __dir__(): - lazy_attrs = list(_dynamic_imports.keys()) - return sorted(lazy_attrs) + lazy_attrs = builtins.list(_dynamic_imports.keys()) + return builtins.sorted(lazy_attrs) diff --git a/sdks/outpost-python/src/outpost_sdk/events.py b/sdks/outpost-python/src/outpost_sdk/events.py index 199e89ab..7911a4e7 100644 --- a/sdks/outpost-python/src/outpost_sdk/events.py +++ b/sdks/outpost-python/src/outpost_sdk/events.py @@ -1,11 +1,13 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" from .basesdk import BaseSDK +from datetime import datetime +from jsonpath import JSONPath from outpost_sdk import errors, models, utils from outpost_sdk._hooks import HookContext from outpost_sdk.types import OptionalNullable, UNSET from outpost_sdk.utils.unmarshal_json_response import unmarshal_json_response -from typing import Any, List, Mapping, Optional, Union +from typing import Any, Dict, List, Mapping, Optional, Union class Events(BaseSDK): @@ -19,11 +21,16 @@ def list( Union[models.DestinationID, models.DestinationIDTypedDict] ] = None, status: Optional[models.ListTenantEventsStatus] = None, + next: Optional[str] = None, + prev: Optional[str] = None, + limit: Optional[int] = 100, + start: Optional[datetime] = None, + end: Optional[datetime] = None, retries: OptionalNullable[utils.RetryConfig] = UNSET, server_url: Optional[str] = None, timeout_ms: Optional[int] = None, http_headers: Optional[Mapping[str, str]] = None, - ) -> List[models.Event]: + ) -> Optional[models.ListTenantEventsResponse]: r"""List Events Retrieves a list of events for the tenant, supporting cursor navigation (details TBD) and filtering. @@ -31,6 +38,11 @@ def list( :param tenant_id: The ID of the tenant. Required when using AdminApiKey authentication. :param destination_id: Filter events by destination ID(s). :param status: Filter events by delivery status. + :param next: Cursor for next page of results + :param prev: Cursor for previous page of results + :param limit: Number of items per page (default 100, max 1000) + :param start: Start time filter (RFC3339 format) + :param end: End time filter (RFC3339 format) :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 @@ -50,6 +62,11 @@ def list( tenant_id=tenant_id, destination_id=destination_id, status=status, + next=next, + prev=prev, + limit=limit, + start=start, + end=end, ) req = self._build_request( @@ -118,9 +135,43 @@ def list( retry_config=retry_config, ) + def next_func() -> Optional[models.ListTenantEventsResponse]: + body = utils.unmarshal_json(http_res.text, Union[Dict[Any, Any], List[Any]]) + next_cursor = JSONPath("$.next").parse(body) + + if len(next_cursor) == 0: + return None + + next_cursor = next_cursor[0] + if next_cursor is None or str(next_cursor).strip() == "": + return None + results = JSONPath("$.data").parse(body) + if len(results) == 0 or len(results[0]) == 0: + return None + limit = request.limit if not request.limit is None else 100 + if len(results[0]) < limit: + return None + + return self.list( + tenant_id=tenant_id, + destination_id=destination_id, + status=status, + next=next_cursor, + prev=prev, + limit=limit, + start=start, + end=end, + retries=retries, + ) + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): - return unmarshal_json_response(List[models.Event], http_res) + return models.ListTenantEventsResponse( + result=unmarshal_json_response( + models.ListTenantEventsResponseBody, http_res + ), + next=next_func, + ) if utils.match_response(http_res, ["401", "403", "407"], "application/json"): response_data = unmarshal_json_response( errors.UnauthorizedErrorData, http_res @@ -181,11 +232,16 @@ async def list_async( Union[models.DestinationID, models.DestinationIDTypedDict] ] = None, status: Optional[models.ListTenantEventsStatus] = None, + next: Optional[str] = None, + prev: Optional[str] = None, + limit: Optional[int] = 100, + start: Optional[datetime] = None, + end: Optional[datetime] = None, retries: OptionalNullable[utils.RetryConfig] = UNSET, server_url: Optional[str] = None, timeout_ms: Optional[int] = None, http_headers: Optional[Mapping[str, str]] = None, - ) -> List[models.Event]: + ) -> Optional[models.ListTenantEventsResponse]: r"""List Events Retrieves a list of events for the tenant, supporting cursor navigation (details TBD) and filtering. @@ -193,6 +249,11 @@ async def list_async( :param tenant_id: The ID of the tenant. Required when using AdminApiKey authentication. :param destination_id: Filter events by destination ID(s). :param status: Filter events by delivery status. + :param next: Cursor for next page of results + :param prev: Cursor for previous page of results + :param limit: Number of items per page (default 100, max 1000) + :param start: Start time filter (RFC3339 format) + :param end: End time filter (RFC3339 format) :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 @@ -212,6 +273,11 @@ async def list_async( tenant_id=tenant_id, destination_id=destination_id, status=status, + next=next, + prev=prev, + limit=limit, + start=start, + end=end, ) req = self._build_request_async( @@ -280,9 +346,43 @@ async def list_async( retry_config=retry_config, ) + def next_func() -> Optional[models.ListTenantEventsResponse]: + body = utils.unmarshal_json(http_res.text, Union[Dict[Any, Any], List[Any]]) + next_cursor = JSONPath("$.next").parse(body) + + if len(next_cursor) == 0: + return None + + next_cursor = next_cursor[0] + if next_cursor is None or str(next_cursor).strip() == "": + return None + results = JSONPath("$.data").parse(body) + if len(results) == 0 or len(results[0]) == 0: + return None + limit = request.limit if not request.limit is None else 100 + if len(results[0]) < limit: + return None + + return self.list( + tenant_id=tenant_id, + destination_id=destination_id, + status=status, + next=next_cursor, + prev=prev, + limit=limit, + start=start, + end=end, + retries=retries, + ) + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): - return unmarshal_json_response(List[models.Event], http_res) + return models.ListTenantEventsResponse( + result=unmarshal_json_response( + models.ListTenantEventsResponseBody, http_res + ), + next=next_func, + ) if utils.match_response(http_res, ["401", "403", "407"], "application/json"): response_data = unmarshal_json_response( errors.UnauthorizedErrorData, http_res @@ -969,11 +1069,16 @@ def list_by_destination( destination_id: str, tenant_id: Optional[str] = None, status: Optional[models.ListTenantEventsByDestinationStatus] = None, + next: Optional[str] = None, + prev: Optional[str] = None, + limit: Optional[int] = 100, + start: Optional[datetime] = None, + end: Optional[datetime] = None, retries: OptionalNullable[utils.RetryConfig] = UNSET, server_url: Optional[str] = None, timeout_ms: Optional[int] = None, http_headers: Optional[Mapping[str, str]] = None, - ) -> List[models.Event]: + ) -> Optional[models.ListTenantEventsByDestinationResponse]: r"""List Events by Destination Retrieves events associated with a specific destination for the tenant. @@ -981,6 +1086,11 @@ def list_by_destination( :param destination_id: The ID of the destination. :param tenant_id: The ID of the tenant. Required when using AdminApiKey authentication. :param status: Filter events by delivery status. + :param next: Cursor for next page of results + :param prev: Cursor for previous page of results + :param limit: Number of items per page (default 100, max 1000) + :param start: Start time filter (RFC3339 format) + :param end: End time filter (RFC3339 format) :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 @@ -1000,6 +1110,11 @@ def list_by_destination( tenant_id=tenant_id, destination_id=destination_id, status=status, + next=next, + prev=prev, + limit=limit, + start=start, + end=end, ) req = self._build_request( @@ -1068,9 +1183,43 @@ def list_by_destination( retry_config=retry_config, ) + def next_func() -> Optional[models.ListTenantEventsByDestinationResponse]: + body = utils.unmarshal_json(http_res.text, Union[Dict[Any, Any], List[Any]]) + next_cursor = JSONPath("$.next").parse(body) + + if len(next_cursor) == 0: + return None + + next_cursor = next_cursor[0] + if next_cursor is None or str(next_cursor).strip() == "": + return None + results = JSONPath("$.data").parse(body) + if len(results) == 0 or len(results[0]) == 0: + return None + limit = request.limit if not request.limit is None else 100 + if len(results[0]) < limit: + return None + + return self.list_by_destination( + destination_id=destination_id, + tenant_id=tenant_id, + status=status, + next=next_cursor, + prev=prev, + limit=limit, + start=start, + end=end, + retries=retries, + ) + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): - return unmarshal_json_response(List[models.Event], http_res) + return models.ListTenantEventsByDestinationResponse( + result=unmarshal_json_response( + models.ListTenantEventsByDestinationResponseBody, http_res + ), + next=next_func, + ) if utils.match_response(http_res, ["401", "403", "407"], "application/json"): response_data = unmarshal_json_response( errors.UnauthorizedErrorData, http_res @@ -1129,11 +1278,16 @@ async def list_by_destination_async( destination_id: str, tenant_id: Optional[str] = None, status: Optional[models.ListTenantEventsByDestinationStatus] = None, + next: Optional[str] = None, + prev: Optional[str] = None, + limit: Optional[int] = 100, + start: Optional[datetime] = None, + end: Optional[datetime] = None, retries: OptionalNullable[utils.RetryConfig] = UNSET, server_url: Optional[str] = None, timeout_ms: Optional[int] = None, http_headers: Optional[Mapping[str, str]] = None, - ) -> List[models.Event]: + ) -> Optional[models.ListTenantEventsByDestinationResponse]: r"""List Events by Destination Retrieves events associated with a specific destination for the tenant. @@ -1141,6 +1295,11 @@ async def list_by_destination_async( :param destination_id: The ID of the destination. :param tenant_id: The ID of the tenant. Required when using AdminApiKey authentication. :param status: Filter events by delivery status. + :param next: Cursor for next page of results + :param prev: Cursor for previous page of results + :param limit: Number of items per page (default 100, max 1000) + :param start: Start time filter (RFC3339 format) + :param end: End time filter (RFC3339 format) :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 @@ -1160,6 +1319,11 @@ async def list_by_destination_async( tenant_id=tenant_id, destination_id=destination_id, status=status, + next=next, + prev=prev, + limit=limit, + start=start, + end=end, ) req = self._build_request_async( @@ -1228,9 +1392,43 @@ async def list_by_destination_async( retry_config=retry_config, ) + def next_func() -> Optional[models.ListTenantEventsByDestinationResponse]: + body = utils.unmarshal_json(http_res.text, Union[Dict[Any, Any], List[Any]]) + next_cursor = JSONPath("$.next").parse(body) + + if len(next_cursor) == 0: + return None + + next_cursor = next_cursor[0] + if next_cursor is None or str(next_cursor).strip() == "": + return None + results = JSONPath("$.data").parse(body) + if len(results) == 0 or len(results[0]) == 0: + return None + limit = request.limit if not request.limit is None else 100 + if len(results[0]) < limit: + return None + + return self.list_by_destination( + destination_id=destination_id, + tenant_id=tenant_id, + status=status, + next=next_cursor, + prev=prev, + limit=limit, + start=start, + end=end, + retries=retries, + ) + response_data: Any = None if utils.match_response(http_res, "200", "application/json"): - return unmarshal_json_response(List[models.Event], http_res) + return models.ListTenantEventsByDestinationResponse( + result=unmarshal_json_response( + models.ListTenantEventsByDestinationResponseBody, http_res + ), + next=next_func, + ) if utils.match_response(http_res, ["401", "403", "407"], "application/json"): response_data = unmarshal_json_response( errors.UnauthorizedErrorData, http_res diff --git a/sdks/outpost-python/src/outpost_sdk/models/__init__.py b/sdks/outpost-python/src/outpost_sdk/models/__init__.py index 21aabc0e..cd108e18 100644 --- a/sdks/outpost-python/src/outpost_sdk/models/__init__.py +++ b/sdks/outpost-python/src/outpost_sdk/models/__init__.py @@ -2,6 +2,8 @@ from typing import TYPE_CHECKING from importlib import import_module +import builtins +import sys if TYPE_CHECKING: from .awskinesisconfig import AWSKinesisConfig, AWSKinesisConfigTypedDict @@ -9,6 +11,8 @@ AWSKinesisCredentials, AWSKinesisCredentialsTypedDict, ) + from .awss3config import Awss3Config, Awss3ConfigTypedDict + from .awss3credentials import Awss3Credentials, Awss3CredentialsTypedDict from .awssqsconfig import AWSSQSConfig, AWSSQSConfigTypedDict from .awssqscredentials import AWSSQSCredentials, AWSSQSCredentialsTypedDict from .azureservicebusconfig import ( @@ -44,6 +48,11 @@ DestinationAWSKinesisType, DestinationAWSKinesisTypedDict, ) + from .destinationawss3 import ( + DestinationAwss3, + DestinationAwss3Type, + DestinationAwss3TypedDict, + ) from .destinationawssqs import ( DestinationAWSSQS, DestinationAWSSQSType, @@ -60,6 +69,11 @@ DestinationCreateAWSKinesisType, DestinationCreateAWSKinesisTypedDict, ) + from .destinationcreateawss3 import ( + DestinationCreateAwss3, + DestinationCreateAwss3Type, + DestinationCreateAwss3TypedDict, + ) from .destinationcreateawssqs import ( DestinationCreateAWSSQS, DestinationCreateAWSSQSType, @@ -109,6 +123,10 @@ DestinationUpdateAWSKinesis, DestinationUpdateAWSKinesisTypedDict, ) + from .destinationupdateawss3 import ( + DestinationUpdateAwss3, + DestinationUpdateAwss3TypedDict, + ) from .destinationupdateawssqs import ( DestinationUpdateAWSSQS, DestinationUpdateAWSSQSTypedDict, @@ -222,6 +240,10 @@ ListTenantEventsByDestinationGlobalsTypedDict, ListTenantEventsByDestinationRequest, ListTenantEventsByDestinationRequestTypedDict, + ListTenantEventsByDestinationResponse, + ListTenantEventsByDestinationResponseBody, + ListTenantEventsByDestinationResponseBodyTypedDict, + ListTenantEventsByDestinationResponseTypedDict, ListTenantEventsByDestinationStatus, ) from .listtenanteventsop import ( @@ -231,6 +253,10 @@ ListTenantEventsGlobalsTypedDict, ListTenantEventsRequest, ListTenantEventsRequestTypedDict, + ListTenantEventsResponse, + ListTenantEventsResponseBody, + ListTenantEventsResponseBodyTypedDict, + ListTenantEventsResponseTypedDict, ListTenantEventsStatus, ) from .listtenanttopicsop import ( @@ -285,6 +311,10 @@ "AWSSQSConfigTypedDict", "AWSSQSCredentials", "AWSSQSCredentialsTypedDict", + "Awss3Config", + "Awss3ConfigTypedDict", + "Awss3Credentials", + "Awss3CredentialsTypedDict", "AzureServiceBusConfig", "AzureServiceBusConfigTypedDict", "AzureServiceBusCredentials", @@ -310,6 +340,9 @@ "DestinationAWSSQS", "DestinationAWSSQSType", "DestinationAWSSQSTypedDict", + "DestinationAwss3", + "DestinationAwss3Type", + "DestinationAwss3TypedDict", "DestinationAzureServiceBus", "DestinationAzureServiceBusType", "DestinationAzureServiceBusTypedDict", @@ -320,6 +353,9 @@ "DestinationCreateAWSSQS", "DestinationCreateAWSSQSType", "DestinationCreateAWSSQSTypedDict", + "DestinationCreateAwss3", + "DestinationCreateAwss3Type", + "DestinationCreateAwss3TypedDict", "DestinationCreateAzureServiceBus", "DestinationCreateAzureServiceBusType", "DestinationCreateAzureServiceBusTypedDict", @@ -352,6 +388,8 @@ "DestinationUpdateAWSKinesisTypedDict", "DestinationUpdateAWSSQS", "DestinationUpdateAWSSQSTypedDict", + "DestinationUpdateAwss3", + "DestinationUpdateAwss3TypedDict", "DestinationUpdateHookdeck", "DestinationUpdateHookdeckTypedDict", "DestinationUpdateRabbitMQ", @@ -426,11 +464,19 @@ "ListTenantEventsByDestinationGlobalsTypedDict", "ListTenantEventsByDestinationRequest", "ListTenantEventsByDestinationRequestTypedDict", + "ListTenantEventsByDestinationResponse", + "ListTenantEventsByDestinationResponseBody", + "ListTenantEventsByDestinationResponseBodyTypedDict", + "ListTenantEventsByDestinationResponseTypedDict", "ListTenantEventsByDestinationStatus", "ListTenantEventsGlobals", "ListTenantEventsGlobalsTypedDict", "ListTenantEventsRequest", "ListTenantEventsRequestTypedDict", + "ListTenantEventsResponse", + "ListTenantEventsResponseBody", + "ListTenantEventsResponseBodyTypedDict", + "ListTenantEventsResponseTypedDict", "ListTenantEventsStatus", "ListTenantTopicsGlobals", "ListTenantTopicsGlobalsTypedDict", @@ -489,6 +535,10 @@ "AWSKinesisConfigTypedDict": ".awskinesisconfig", "AWSKinesisCredentials": ".awskinesiscredentials", "AWSKinesisCredentialsTypedDict": ".awskinesiscredentials", + "Awss3Config": ".awss3config", + "Awss3ConfigTypedDict": ".awss3config", + "Awss3Credentials": ".awss3credentials", + "Awss3CredentialsTypedDict": ".awss3credentials", "AWSSQSConfig": ".awssqsconfig", "AWSSQSConfigTypedDict": ".awssqsconfig", "AWSSQSCredentials": ".awssqscredentials", @@ -517,6 +567,9 @@ "DestinationAWSKinesis": ".destinationawskinesis", "DestinationAWSKinesisType": ".destinationawskinesis", "DestinationAWSKinesisTypedDict": ".destinationawskinesis", + "DestinationAwss3": ".destinationawss3", + "DestinationAwss3Type": ".destinationawss3", + "DestinationAwss3TypedDict": ".destinationawss3", "DestinationAWSSQS": ".destinationawssqs", "DestinationAWSSQSType": ".destinationawssqs", "DestinationAWSSQSTypedDict": ".destinationawssqs", @@ -528,6 +581,9 @@ "DestinationCreateAWSKinesis": ".destinationcreateawskinesis", "DestinationCreateAWSKinesisType": ".destinationcreateawskinesis", "DestinationCreateAWSKinesisTypedDict": ".destinationcreateawskinesis", + "DestinationCreateAwss3": ".destinationcreateawss3", + "DestinationCreateAwss3Type": ".destinationcreateawss3", + "DestinationCreateAwss3TypedDict": ".destinationcreateawss3", "DestinationCreateAWSSQS": ".destinationcreateawssqs", "DestinationCreateAWSSQSType": ".destinationcreateawssqs", "DestinationCreateAWSSQSTypedDict": ".destinationcreateawssqs", @@ -558,6 +614,8 @@ "DestinationUpdateTypedDict": ".destinationupdate", "DestinationUpdateAWSKinesis": ".destinationupdateawskinesis", "DestinationUpdateAWSKinesisTypedDict": ".destinationupdateawskinesis", + "DestinationUpdateAwss3": ".destinationupdateawss3", + "DestinationUpdateAwss3TypedDict": ".destinationupdateawss3", "DestinationUpdateAWSSQS": ".destinationupdateawssqs", "DestinationUpdateAWSSQSTypedDict": ".destinationupdateawssqs", "DestinationUpdateHookdeck": ".destinationupdatehookdeck", @@ -636,6 +694,10 @@ "ListTenantEventsByDestinationGlobalsTypedDict": ".listtenanteventsbydestinationop", "ListTenantEventsByDestinationRequest": ".listtenanteventsbydestinationop", "ListTenantEventsByDestinationRequestTypedDict": ".listtenanteventsbydestinationop", + "ListTenantEventsByDestinationResponse": ".listtenanteventsbydestinationop", + "ListTenantEventsByDestinationResponseBody": ".listtenanteventsbydestinationop", + "ListTenantEventsByDestinationResponseBodyTypedDict": ".listtenanteventsbydestinationop", + "ListTenantEventsByDestinationResponseTypedDict": ".listtenanteventsbydestinationop", "ListTenantEventsByDestinationStatus": ".listtenanteventsbydestinationop", "DestinationID": ".listtenanteventsop", "DestinationIDTypedDict": ".listtenanteventsop", @@ -643,6 +705,10 @@ "ListTenantEventsGlobalsTypedDict": ".listtenanteventsop", "ListTenantEventsRequest": ".listtenanteventsop", "ListTenantEventsRequestTypedDict": ".listtenanteventsop", + "ListTenantEventsResponse": ".listtenanteventsop", + "ListTenantEventsResponseBody": ".listtenanteventsop", + "ListTenantEventsResponseBodyTypedDict": ".listtenanteventsop", + "ListTenantEventsResponseTypedDict": ".listtenanteventsop", "ListTenantEventsStatus": ".listtenanteventsop", "ListTenantTopicsGlobals": ".listtenanttopicsop", "ListTenantTopicsGlobalsTypedDict": ".listtenanttopicsop", @@ -693,6 +759,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: @@ -701,7 +779,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: @@ -715,5 +793,5 @@ def __getattr__(attr_name: str) -> object: def __dir__(): - lazy_attrs = list(_dynamic_imports.keys()) - return sorted(lazy_attrs) + lazy_attrs = builtins.list(_dynamic_imports.keys()) + return builtins.sorted(lazy_attrs) diff --git a/sdks/outpost-python/src/outpost_sdk/models/awss3config.py b/sdks/outpost-python/src/outpost_sdk/models/awss3config.py new file mode 100644 index 00000000..477feec5 --- /dev/null +++ b/sdks/outpost-python/src/outpost_sdk/models/awss3config.py @@ -0,0 +1,31 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from outpost_sdk.types import BaseModel +from typing import Optional +from typing_extensions import NotRequired, TypedDict + + +class Awss3ConfigTypedDict(TypedDict): + bucket: str + r"""The name of your AWS S3 bucket.""" + region: str + r"""The AWS region where your bucket is located.""" + key_template: NotRequired[str] + r"""JMESPath expression for generating S3 object keys. Default is join('', [time.rfc3339_nano, '_', metadata.\"event-id\", '.json']).""" + storage_class: NotRequired[str] + r"""The storage class for the S3 objects (e.g., STANDARD, INTELLIGENT_TIERING, GLACIER, etc.). Defaults to \"STANDARD\".""" + + +class Awss3Config(BaseModel): + bucket: str + r"""The name of your AWS S3 bucket.""" + + region: str + r"""The AWS region where your bucket is located.""" + + key_template: Optional[str] = None + r"""JMESPath expression for generating S3 object keys. Default is join('', [time.rfc3339_nano, '_', metadata.\"event-id\", '.json']).""" + + storage_class: Optional[str] = None + r"""The storage class for the S3 objects (e.g., STANDARD, INTELLIGENT_TIERING, GLACIER, etc.). Defaults to \"STANDARD\".""" diff --git a/sdks/outpost-python/src/outpost_sdk/models/awss3credentials.py b/sdks/outpost-python/src/outpost_sdk/models/awss3credentials.py new file mode 100644 index 00000000..460fd74d --- /dev/null +++ b/sdks/outpost-python/src/outpost_sdk/models/awss3credentials.py @@ -0,0 +1,26 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from outpost_sdk.types import BaseModel +from typing import Optional +from typing_extensions import NotRequired, TypedDict + + +class Awss3CredentialsTypedDict(TypedDict): + key: str + r"""AWS Access Key ID.""" + secret: str + r"""AWS Secret Access Key.""" + session: NotRequired[str] + r"""Optional AWS Session Token (for temporary credentials).""" + + +class Awss3Credentials(BaseModel): + key: str + r"""AWS Access Key ID.""" + + secret: str + r"""AWS Secret Access Key.""" + + session: Optional[str] = None + r"""Optional AWS Session Token (for temporary credentials).""" diff --git a/sdks/outpost-python/src/outpost_sdk/models/destination.py b/sdks/outpost-python/src/outpost_sdk/models/destination.py index d9ffe064..5f47ca69 100644 --- a/sdks/outpost-python/src/outpost_sdk/models/destination.py +++ b/sdks/outpost-python/src/outpost_sdk/models/destination.py @@ -2,6 +2,7 @@ from __future__ import annotations from .destinationawskinesis import DestinationAWSKinesis, DestinationAWSKinesisTypedDict +from .destinationawss3 import DestinationAwss3, DestinationAwss3TypedDict from .destinationawssqs import DestinationAWSSQS, DestinationAWSSQSTypedDict from .destinationazureservicebus import ( DestinationAzureServiceBus, @@ -25,6 +26,7 @@ DestinationHookdeckTypedDict, DestinationAWSKinesisTypedDict, DestinationAzureServiceBusTypedDict, + DestinationAwss3TypedDict, ], ) @@ -37,6 +39,7 @@ Annotated[DestinationHookdeck, Tag("hookdeck")], Annotated[DestinationAWSKinesis, Tag("aws_kinesis")], Annotated[DestinationAzureServiceBus, Tag("azure_servicebus")], + Annotated[DestinationAwss3, Tag("aws_s3")], ], Discriminator(lambda m: get_discriminator(m, "type", "type")), ] diff --git a/sdks/outpost-python/src/outpost_sdk/models/destinationawss3.py b/sdks/outpost-python/src/outpost_sdk/models/destinationawss3.py new file mode 100644 index 00000000..52db47b4 --- /dev/null +++ b/sdks/outpost-python/src/outpost_sdk/models/destinationawss3.py @@ -0,0 +1,100 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from .awss3config import Awss3Config, Awss3ConfigTypedDict +from .awss3credentials import Awss3Credentials, Awss3CredentialsTypedDict +from .topics_union import TopicsUnion, TopicsUnionTypedDict +from datetime import datetime +from enum import Enum +from outpost_sdk.types import ( + BaseModel, + Nullable, + OptionalNullable, + UNSET, + UNSET_SENTINEL, +) +from pydantic import model_serializer +from typing import Optional +from typing_extensions import NotRequired, TypedDict + + +class DestinationAwss3Type(str, Enum): + r"""Type of the destination.""" + + AWS_S3 = "aws_s3" + + +class DestinationAwss3TypedDict(TypedDict): + id: str + r"""Control plane generated ID or user provided ID for the destination.""" + type: DestinationAwss3Type + r"""Type of the destination.""" + topics: TopicsUnionTypedDict + r"""\"*\" or an array of enabled topics.""" + disabled_at: Nullable[datetime] + r"""ISO Date when the destination was disabled, or null if enabled.""" + created_at: datetime + r"""ISO Date when the destination was created.""" + config: Awss3ConfigTypedDict + credentials: Awss3CredentialsTypedDict + target: NotRequired[str] + r"""A human-readable representation of the destination target (bucket and region). Read-only.""" + target_url: NotRequired[Nullable[str]] + r"""A URL link to the destination target (AWS Console link to the bucket). Read-only.""" + + +class DestinationAwss3(BaseModel): + id: str + r"""Control plane generated ID or user provided ID for the destination.""" + + type: DestinationAwss3Type + r"""Type of the destination.""" + + topics: TopicsUnion + r"""\"*\" or an array of enabled topics.""" + + disabled_at: Nullable[datetime] + r"""ISO Date when the destination was disabled, or null if enabled.""" + + created_at: datetime + r"""ISO Date when the destination was created.""" + + config: Awss3Config + + credentials: Awss3Credentials + + target: Optional[str] = None + r"""A human-readable representation of the destination target (bucket and region). Read-only.""" + + target_url: OptionalNullable[str] = UNSET + r"""A URL link to the destination target (AWS Console link to the bucket). Read-only.""" + + @model_serializer(mode="wrap") + def serialize_model(self, handler): + optional_fields = ["target", "target_url"] + nullable_fields = ["disabled_at", "target_url"] + null_default_fields = [] + + serialized = handler(self) + + m = {} + + for n, f in type(self).model_fields.items(): + k = f.alias or n + val = serialized.get(k) + serialized.pop(k, None) + + optional_nullable = k in optional_fields and k in nullable_fields + is_set = ( + self.__pydantic_fields_set__.intersection({n}) + or k in null_default_fields + ) # pylint: disable=no-member + + if val is not None and val != UNSET_SENTINEL: + m[k] = val + elif val != UNSET_SENTINEL and ( + not k in optional_fields or (optional_nullable and is_set) + ): + m[k] = val + + return m diff --git a/sdks/outpost-python/src/outpost_sdk/models/destinationcreate.py b/sdks/outpost-python/src/outpost_sdk/models/destinationcreate.py index 7185e1d6..3905168d 100644 --- a/sdks/outpost-python/src/outpost_sdk/models/destinationcreate.py +++ b/sdks/outpost-python/src/outpost_sdk/models/destinationcreate.py @@ -5,6 +5,10 @@ DestinationCreateAWSKinesis, DestinationCreateAWSKinesisTypedDict, ) +from .destinationcreateawss3 import ( + DestinationCreateAwss3, + DestinationCreateAwss3TypedDict, +) from .destinationcreateawssqs import ( DestinationCreateAWSSQS, DestinationCreateAWSSQSTypedDict, @@ -40,6 +44,7 @@ DestinationCreateHookdeckTypedDict, DestinationCreateAWSKinesisTypedDict, DestinationCreateAzureServiceBusTypedDict, + DestinationCreateAwss3TypedDict, ], ) @@ -52,6 +57,7 @@ Annotated[DestinationCreateHookdeck, Tag("hookdeck")], Annotated[DestinationCreateAWSKinesis, Tag("aws_kinesis")], Annotated[DestinationCreateAzureServiceBus, Tag("azure_servicebus")], + Annotated[DestinationCreateAwss3, Tag("aws_s3")], ], Discriminator(lambda m: get_discriminator(m, "type", "type")), ] diff --git a/sdks/outpost-python/src/outpost_sdk/models/destinationcreateawss3.py b/sdks/outpost-python/src/outpost_sdk/models/destinationcreateawss3.py new file mode 100644 index 00000000..a4a195c9 --- /dev/null +++ b/sdks/outpost-python/src/outpost_sdk/models/destinationcreateawss3.py @@ -0,0 +1,42 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from .awss3config import Awss3Config, Awss3ConfigTypedDict +from .awss3credentials import Awss3Credentials, Awss3CredentialsTypedDict +from .topics_union import TopicsUnion, TopicsUnionTypedDict +from enum import Enum +from outpost_sdk.types import BaseModel +from typing import Optional +from typing_extensions import NotRequired, TypedDict + + +class DestinationCreateAwss3Type(str, Enum): + r"""Type of the destination. Must be 'aws_s3'.""" + + AWS_S3 = "aws_s3" + + +class DestinationCreateAwss3TypedDict(TypedDict): + type: DestinationCreateAwss3Type + r"""Type of the destination. Must be 'aws_s3'.""" + topics: TopicsUnionTypedDict + r"""\"*\" or an array of enabled topics.""" + config: Awss3ConfigTypedDict + credentials: Awss3CredentialsTypedDict + id: NotRequired[str] + r"""Optional user-provided ID. A UUID will be generated if empty.""" + + +class DestinationCreateAwss3(BaseModel): + type: DestinationCreateAwss3Type + r"""Type of the destination. Must be 'aws_s3'.""" + + topics: TopicsUnion + r"""\"*\" or an array of enabled topics.""" + + config: Awss3Config + + credentials: Awss3Credentials + + id: Optional[str] = None + r"""Optional user-provided ID. A UUID will be generated if empty.""" diff --git a/sdks/outpost-python/src/outpost_sdk/models/destinationupdate.py b/sdks/outpost-python/src/outpost_sdk/models/destinationupdate.py index f2ccbcd9..80b43c91 100644 --- a/sdks/outpost-python/src/outpost_sdk/models/destinationupdate.py +++ b/sdks/outpost-python/src/outpost_sdk/models/destinationupdate.py @@ -5,6 +5,10 @@ DestinationUpdateAWSKinesis, DestinationUpdateAWSKinesisTypedDict, ) +from .destinationupdateawss3 import ( + DestinationUpdateAwss3, + DestinationUpdateAwss3TypedDict, +) from .destinationupdateawssqs import ( DestinationUpdateAWSSQS, DestinationUpdateAWSSQSTypedDict, @@ -33,6 +37,7 @@ DestinationUpdateRabbitMQTypedDict, DestinationUpdateHookdeckTypedDict, DestinationUpdateAWSKinesisTypedDict, + DestinationUpdateAwss3TypedDict, ], ) @@ -45,5 +50,6 @@ DestinationUpdateRabbitMQ, DestinationUpdateHookdeck, DestinationUpdateAWSKinesis, + DestinationUpdateAwss3, ], ) diff --git a/sdks/outpost-python/src/outpost_sdk/models/destinationupdateawss3.py b/sdks/outpost-python/src/outpost_sdk/models/destinationupdateawss3.py new file mode 100644 index 00000000..8760e8ee --- /dev/null +++ b/sdks/outpost-python/src/outpost_sdk/models/destinationupdateawss3.py @@ -0,0 +1,25 @@ +"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" + +from __future__ import annotations +from .awss3config import Awss3Config, Awss3ConfigTypedDict +from .awss3credentials import Awss3Credentials, Awss3CredentialsTypedDict +from .topics_union import TopicsUnion, TopicsUnionTypedDict +from outpost_sdk.types import BaseModel +from typing import Optional +from typing_extensions import NotRequired, TypedDict + + +class DestinationUpdateAwss3TypedDict(TypedDict): + topics: NotRequired[TopicsUnionTypedDict] + r"""\"*\" or an array of enabled topics.""" + config: NotRequired[Awss3ConfigTypedDict] + credentials: NotRequired[Awss3CredentialsTypedDict] + + +class DestinationUpdateAwss3(BaseModel): + topics: Optional[TopicsUnion] = None + r"""\"*\" or an array of enabled topics.""" + + config: Optional[Awss3Config] = None + + credentials: Optional[Awss3Credentials] = None diff --git a/sdks/outpost-python/src/outpost_sdk/models/getdestinationtypeschemaop.py b/sdks/outpost-python/src/outpost_sdk/models/getdestinationtypeschemaop.py index 120fbd21..8c99b9e5 100644 --- a/sdks/outpost-python/src/outpost_sdk/models/getdestinationtypeschemaop.py +++ b/sdks/outpost-python/src/outpost_sdk/models/getdestinationtypeschemaop.py @@ -15,6 +15,7 @@ class GetDestinationTypeSchemaType(str, Enum): RABBITMQ = "rabbitmq" HOOKDECK = "hookdeck" AWS_KINESIS = "aws_kinesis" + AWS_S3 = "aws_s3" class GetDestinationTypeSchemaRequestTypedDict(TypedDict): diff --git a/sdks/outpost-python/src/outpost_sdk/models/gettenantdestinationtypeschemaop.py b/sdks/outpost-python/src/outpost_sdk/models/gettenantdestinationtypeschemaop.py index 3147cd33..536b7c51 100644 --- a/sdks/outpost-python/src/outpost_sdk/models/gettenantdestinationtypeschemaop.py +++ b/sdks/outpost-python/src/outpost_sdk/models/gettenantdestinationtypeschemaop.py @@ -27,6 +27,7 @@ class GetTenantDestinationTypeSchemaType(str, Enum): RABBITMQ = "rabbitmq" HOOKDECK = "hookdeck" AWS_KINESIS = "aws_kinesis" + AWS_S3 = "aws_s3" class GetTenantDestinationTypeSchemaRequestTypedDict(TypedDict): diff --git a/sdks/outpost-python/src/outpost_sdk/models/internal/__init__.py b/sdks/outpost-python/src/outpost_sdk/models/internal/__init__.py index ff432150..e7070a12 100644 --- a/sdks/outpost-python/src/outpost_sdk/models/internal/__init__.py +++ b/sdks/outpost-python/src/outpost_sdk/models/internal/__init__.py @@ -2,6 +2,8 @@ from typing import TYPE_CHECKING from importlib import import_module +import builtins +import sys if TYPE_CHECKING: from .globals import Globals, GlobalsTypedDict @@ -14,6 +16,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: @@ -22,7 +36,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: @@ -36,5 +50,5 @@ def __getattr__(attr_name: str) -> object: def __dir__(): - lazy_attrs = list(_dynamic_imports.keys()) - return sorted(lazy_attrs) + lazy_attrs = builtins.list(_dynamic_imports.keys()) + return builtins.sorted(lazy_attrs) diff --git a/sdks/outpost-python/src/outpost_sdk/models/listtenantdestinationsop.py b/sdks/outpost-python/src/outpost_sdk/models/listtenantdestinationsop.py index 0d378eaf..5746a0f1 100644 --- a/sdks/outpost-python/src/outpost_sdk/models/listtenantdestinationsop.py +++ b/sdks/outpost-python/src/outpost_sdk/models/listtenantdestinationsop.py @@ -25,6 +25,7 @@ class ListTenantDestinationsTypeEnum2(str, Enum): RABBITMQ = "rabbitmq" HOOKDECK = "hookdeck" AWS_KINESIS = "aws_kinesis" + AWS_S3 = "aws_s3" class ListTenantDestinationsTypeEnum1(str, Enum): @@ -33,6 +34,7 @@ class ListTenantDestinationsTypeEnum1(str, Enum): RABBITMQ = "rabbitmq" HOOKDECK = "hookdeck" AWS_KINESIS = "aws_kinesis" + AWS_S3 = "aws_s3" TypeTypedDict = TypeAliasType( diff --git a/sdks/outpost-python/src/outpost_sdk/models/listtenanteventsbydestinationop.py b/sdks/outpost-python/src/outpost_sdk/models/listtenanteventsbydestinationop.py index d11ba995..d69471bc 100644 --- a/sdks/outpost-python/src/outpost_sdk/models/listtenanteventsbydestinationop.py +++ b/sdks/outpost-python/src/outpost_sdk/models/listtenanteventsbydestinationop.py @@ -1,10 +1,13 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" from __future__ import annotations +from .event import Event, EventTypedDict +from datetime import datetime from enum import Enum from outpost_sdk.types import BaseModel from outpost_sdk.utils import FieldMetadata, PathParamMetadata, QueryParamMetadata -from typing import Optional +import pydantic +from typing import Callable, List, Optional from typing_extensions import Annotated, NotRequired, TypedDict @@ -33,6 +36,16 @@ class ListTenantEventsByDestinationRequestTypedDict(TypedDict): r"""The ID of the tenant. Required when using AdminApiKey authentication.""" status: NotRequired[ListTenantEventsByDestinationStatus] r"""Filter events by delivery status.""" + next: NotRequired[str] + r"""Cursor for next page of results""" + prev: NotRequired[str] + r"""Cursor for previous page of results""" + limit: NotRequired[int] + r"""Number of items per page (default 100, max 1000)""" + start: NotRequired[datetime] + r"""Start time filter (RFC3339 format)""" + end: NotRequired[datetime] + r"""End time filter (RFC3339 format)""" class ListTenantEventsByDestinationRequest(BaseModel): @@ -52,3 +65,70 @@ class ListTenantEventsByDestinationRequest(BaseModel): FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), ] = None r"""Filter events by delivery status.""" + + next: Annotated[ + Optional[str], + FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), + ] = None + r"""Cursor for next page of results""" + + prev: Annotated[ + Optional[str], + FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), + ] = None + r"""Cursor for previous page of results""" + + limit: Annotated[ + Optional[int], + FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), + ] = 100 + r"""Number of items per page (default 100, max 1000)""" + + start: Annotated[ + Optional[datetime], + FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), + ] = None + r"""Start time filter (RFC3339 format)""" + + end: Annotated[ + Optional[datetime], + FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), + ] = None + r"""End time filter (RFC3339 format)""" + + +class ListTenantEventsByDestinationResponseBodyTypedDict(TypedDict): + r"""A paginated list of events for the destination.""" + + count: int + r"""Total number of items across all pages""" + data: List[EventTypedDict] + next_cursor: str + r"""Cursor for next page (empty string if no next page)""" + prev_cursor: str + r"""Cursor for previous page (empty string if no previous page)""" + + +class ListTenantEventsByDestinationResponseBody(BaseModel): + r"""A paginated list of events for the destination.""" + + count: int + r"""Total number of items across all pages""" + + data: List[Event] + + next_cursor: Annotated[str, pydantic.Field(alias="next")] + r"""Cursor for next page (empty string if no next page)""" + + prev_cursor: Annotated[str, pydantic.Field(alias="prev")] + r"""Cursor for previous page (empty string if no previous page)""" + + +class ListTenantEventsByDestinationResponseTypedDict(TypedDict): + result: ListTenantEventsByDestinationResponseBodyTypedDict + + +class ListTenantEventsByDestinationResponse(BaseModel): + next: Callable[[], Optional[ListTenantEventsByDestinationResponse]] + + result: ListTenantEventsByDestinationResponseBody diff --git a/sdks/outpost-python/src/outpost_sdk/models/listtenanteventsop.py b/sdks/outpost-python/src/outpost_sdk/models/listtenanteventsop.py index 7ee10dba..75f1c32e 100644 --- a/sdks/outpost-python/src/outpost_sdk/models/listtenanteventsop.py +++ b/sdks/outpost-python/src/outpost_sdk/models/listtenanteventsop.py @@ -1,10 +1,13 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" from __future__ import annotations +from .event import Event, EventTypedDict +from datetime import datetime from enum import Enum from outpost_sdk.types import BaseModel from outpost_sdk.utils import FieldMetadata, PathParamMetadata, QueryParamMetadata -from typing import List, Optional, Union +import pydantic +from typing import Callable, List, Optional, Union from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict @@ -41,6 +44,16 @@ class ListTenantEventsRequestTypedDict(TypedDict): r"""Filter events by destination ID(s).""" status: NotRequired[ListTenantEventsStatus] r"""Filter events by delivery status.""" + next: NotRequired[str] + r"""Cursor for next page of results""" + prev: NotRequired[str] + r"""Cursor for previous page of results""" + limit: NotRequired[int] + r"""Number of items per page (default 100, max 1000)""" + start: NotRequired[datetime] + r"""Start time filter (RFC3339 format)""" + end: NotRequired[datetime] + r"""End time filter (RFC3339 format)""" class ListTenantEventsRequest(BaseModel): @@ -61,3 +74,70 @@ class ListTenantEventsRequest(BaseModel): FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), ] = None r"""Filter events by delivery status.""" + + next: Annotated[ + Optional[str], + FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), + ] = None + r"""Cursor for next page of results""" + + prev: Annotated[ + Optional[str], + FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), + ] = None + r"""Cursor for previous page of results""" + + limit: Annotated[ + Optional[int], + FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), + ] = 100 + r"""Number of items per page (default 100, max 1000)""" + + start: Annotated[ + Optional[datetime], + FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), + ] = None + r"""Start time filter (RFC3339 format)""" + + end: Annotated[ + Optional[datetime], + FieldMetadata(query=QueryParamMetadata(style="form", explode=True)), + ] = None + r"""End time filter (RFC3339 format)""" + + +class ListTenantEventsResponseBodyTypedDict(TypedDict): + r"""A paginated list of events.""" + + count: int + r"""Total number of items across all pages""" + data: List[EventTypedDict] + next_cursor: str + r"""Cursor for next page (empty string if no next page)""" + prev_cursor: str + r"""Cursor for previous page (empty string if no previous page)""" + + +class ListTenantEventsResponseBody(BaseModel): + r"""A paginated list of events.""" + + count: int + r"""Total number of items across all pages""" + + data: List[Event] + + next_cursor: Annotated[str, pydantic.Field(alias="next")] + r"""Cursor for next page (empty string if no next page)""" + + prev_cursor: Annotated[str, pydantic.Field(alias="prev")] + r"""Cursor for previous page (empty string if no previous page)""" + + +class ListTenantEventsResponseTypedDict(TypedDict): + result: ListTenantEventsResponseBodyTypedDict + + +class ListTenantEventsResponse(BaseModel): + next: Callable[[], Optional[ListTenantEventsResponse]] + + result: ListTenantEventsResponseBody diff --git a/sdks/outpost-python/src/outpost_sdk/sdk.py b/sdks/outpost-python/src/outpost_sdk/sdk.py index 41458e6e..a6ad0602 100644 --- a/sdks/outpost-python/src/outpost_sdk/sdk.py +++ b/sdks/outpost-python/src/outpost_sdk/sdk.py @@ -11,6 +11,7 @@ from outpost_sdk._hooks import SDKHooks from outpost_sdk.models import internal from outpost_sdk.types import OptionalNullable, UNSET +import sys from typing import Callable, Dict, Optional, TYPE_CHECKING, Union, cast import weakref @@ -150,6 +151,7 @@ def __init__( timeout_ms=timeout_ms, debug_logger=debug_logger, ), + parent_ref=self, ) hooks = SDKHooks() @@ -174,13 +176,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: diff --git a/sdks/outpost-python/src/outpost_sdk/utils/__init__.py b/sdks/outpost-python/src/outpost_sdk/utils/__init__.py index dd4aa4b3..56164cf3 100644 --- a/sdks/outpost-python/src/outpost_sdk/utils/__init__.py +++ b/sdks/outpost-python/src/outpost_sdk/utils/__init__.py @@ -2,6 +2,8 @@ from typing import TYPE_CHECKING from importlib import import_module +import builtins +import sys if TYPE_CHECKING: from .annotations import get_discriminator @@ -158,6 +160,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: @@ -166,9 +180,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}" @@ -180,5 +193,5 @@ def __getattr__(attr_name: str) -> object: def __dir__(): - lazy_attrs = list(_dynamic_imports.keys()) - return sorted(lazy_attrs) + lazy_attrs = builtins.list(_dynamic_imports.keys()) + return builtins.sorted(lazy_attrs) diff --git a/sdks/outpost-python/src/outpost_sdk/utils/eventstreaming.py b/sdks/outpost-python/src/outpost_sdk/utils/eventstreaming.py index 74a63f75..0969899b 100644 --- a/sdks/outpost-python/src/outpost_sdk/utils/eventstreaming.py +++ b/sdks/outpost-python/src/outpost_sdk/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/sdks/schemas/pagination-fixes-overlay.yaml b/sdks/schemas/pagination-fixes-overlay.yaml new file mode 100644 index 00000000..3782646e --- /dev/null +++ b/sdks/schemas/pagination-fixes-overlay.yaml @@ -0,0 +1,63 @@ +overlay: 1.0.0 +x-speakeasy-jsonpath: rfc9535 +info: + title: Pagination Field Fixes + version: 0.0.1 + x-speakeasy-metadata: + type: pagination-fixes + description: "Fixes pagination field conflicts with Python built-ins" +extends: file:///Users/leggetter/hookdeck/git/outpost/docs/apis/openapi.yaml +actions: + # Fix 'next' field conflict with Python's built-in next() function + - target: $["components"]["schemas"]["PaginatedResponse"]["properties"]["next"] + update: + x-speakeasy-name-override: "next_cursor" + x-speakeasy-metadata: + type: field-name-override + description: "Rename 'next' to 'next_cursor' to avoid Python built-in conflict" + + # Fix 'prev' field for consistency + - target: $["components"]["schemas"]["PaginatedResponse"]["properties"]["prev"] + update: + x-speakeasy-name-override: "prev_cursor" + x-speakeasy-metadata: + type: field-name-override + description: "Rename 'prev' to 'prev_cursor' for consistency" + + # Add pagination configuration for events endpoint + - target: $["paths"]["/{tenant_id}/events"]["get"] + update: + x-speakeasy-pagination: + type: cursor + inputs: + - name: next + in: parameters + type: cursor + - name: limit + in: parameters + type: limit + outputs: + nextCursor: $.next + results: $.data + x-speakeasy-metadata: + type: pagination-config + description: "Configure cursor-based pagination for events listing" + + # Add pagination configuration for destination events endpoint + - target: $["paths"]["/{tenant_id}/destinations/{destination_id}/events"]["get"] + update: + x-speakeasy-pagination: + type: cursor + inputs: + - name: next + in: parameters + type: cursor + - name: limit + in: parameters + type: limit + outputs: + nextCursor: $.next + results: $.data + x-speakeasy-metadata: + type: pagination-config + description: "Configure cursor-based pagination for destination events listing" \ No newline at end of file