From 8078c01dcc1f3d1adcc757d5eea96f2f8f6fb9fa Mon Sep 17 00:00:00 2001 From: speakeasybot Date: Mon, 15 Sep 2025 00:11:56 +0000 Subject: [PATCH] ## Python SDK Changes Detected: * `unstructured_client.destinations.create_destination()`: * `request.create_destination_connector.config.[azure_destination_connector_config_input]` **Added** * `response.config.[azure_destination_connector_config]` **Added** * `unstructured_client.destinations.get_destination()`: `response.config.[azure_destination_connector_config]` **Added** * `unstructured_client.destinations.list_destinations()`: * `request.destination_type` **Changed** * `response.[].config.[azure_destination_connector_config]` **Added** * `unstructured_client.destinations.update_destination()`: * `request.update_destination_connector.config.[azure_destination_connector_config_input]` **Added** * `response.config.[azure_destination_connector_config]` **Added** --- .gitignore | 1 + .speakeasy/gen.lock | 21 ++++++++----- .speakeasy/workflow.lock | 16 +++++----- RELEASES.md | 12 ++++++- codeSamples.yaml | 4 +-- docs/models/shared/config.md | 6 ++++ .../destinationconnectorinformationconfig.md | 6 ++++ .../models/shared/destinationconnectortype.md | 1 + .../updatedestinationconnectorconfig.md | 6 ++++ gen.yaml | 7 ++++- pyproject.toml | 3 +- scripts/prepare_readme.py | 5 +++ src/unstructured_client/_version.py | 8 ++--- src/unstructured_client/basesdk.py | 12 ++++++- .../models/errors/__init__.py | 18 +++++++++-- .../models/errors/httpvalidationerror.py | 6 ++-- .../models/errors/no_response_error.py | 6 +++- .../models/errors/responsevalidationerror.py | 2 ++ .../models/errors/sdkerror.py | 2 ++ .../models/errors/servererror.py | 6 ++-- .../models/errors/unstructuredclienterror.py | 18 ++++++----- .../models/operations/__init__.py | 15 ++++++++- .../models/shared/__init__.py | 31 ++++++++++++++++++- .../shared/createdestinationconnector.py | 14 ++++++--- .../shared/destinationconnectorinformation.py | 14 ++++++--- .../models/shared/destinationconnectortype.py | 1 + .../shared/updatedestinationconnector.py | 14 ++++++--- src/unstructured_client/sdk.py | 17 ++++++++-- src/unstructured_client/utils/__init__.py | 18 +++++++++-- .../utils/eventstreaming.py | 10 ++++++ 30 files changed, 240 insertions(+), 60 deletions(-) diff --git a/.gitignore b/.gitignore index 14e788bb..51b89173 100755 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.env.local **/__pycache__/ **/.speakeasy/temp/ **/.speakeasy/logs/ diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 578a0905..becbef37 100755 --- a/.speakeasy/gen.lock +++ b/.speakeasy/gen.lock @@ -1,12 +1,12 @@ lockVersion: 2.0.0 id: 8b5fa338-9106-4734-abf0-e30d67044a90 management: - docChecksum: 8038a5b9e376d44bad2fd4c117922954 - docVersion: 1.1.45 - speakeasyVersion: 1.601.0 - generationVersion: 2.680.0 - releaseVersion: 0.42.3 - configChecksum: 3d02dd7ca437781b3d721fab5d7b9adc + docChecksum: adbc2b975ff4cc2c5578a5dd0d51e152 + docVersion: 1.1.47 + speakeasyVersion: 1.615.2 + generationVersion: 2.698.4 + releaseVersion: 0.43.0 + configChecksum: aa508e741e22e8bcf191aa310680d956 repoURL: https://github.com/Unstructured-IO/unstructured-python-client.git repoSubDirectory: . installationURL: https://github.com/Unstructured-IO/unstructured-python-client.git @@ -16,13 +16,13 @@ features: acceptHeaders: 3.0.0 additionalDependencies: 1.0.0 constsAndDefaults: 1.0.5 - core: 5.19.8 + core: 5.20.4 customCodeRegions: 0.1.1 defaultEnabledRetries: 0.2.0 enumUnions: 0.1.0 envVarSecurityUsage: 0.3.2 examples: 3.0.2 - globalSecurity: 3.0.3 + globalSecurity: 3.0.4 globalSecurityCallbacks: 1.0.0 globalSecurityFlattening: 1.0.0 globalServerURLs: 3.1.1 @@ -101,6 +101,8 @@ generatedFiles: - docs/models/shared/astradbconnectorconfiginput.md - docs/models/shared/azureaisearchconnectorconfig.md - docs/models/shared/azureaisearchconnectorconfiginput.md + - docs/models/shared/azuredestinationconnectorconfig.md + - docs/models/shared/azuredestinationconnectorconfiginput.md - docs/models/shared/azuresourceconnectorconfig.md - docs/models/shared/azuresourceconnectorconfiginput.md - docs/models/shared/bodyrunworkflow.md @@ -287,6 +289,8 @@ generatedFiles: - src/unstructured_client/models/shared/astradbconnectorconfiginput.py - src/unstructured_client/models/shared/azureaisearchconnectorconfig.py - src/unstructured_client/models/shared/azureaisearchconnectorconfiginput.py + - src/unstructured_client/models/shared/azuredestinationconnectorconfig.py + - src/unstructured_client/models/shared/azuredestinationconnectorconfiginput.py - src/unstructured_client/models/shared/azuresourceconnectorconfig.py - src/unstructured_client/models/shared/azuresourceconnectorconfiginput.py - src/unstructured_client/models/shared/body_run_workflow.py @@ -712,3 +716,4 @@ examples: application/json: {"detail": []} examplesVersion: 1.0.2 generatedTests: {} +releaseNotes: "## Python SDK Changes Detected:\n* `unstructured_client.destinations.create_destination()`: \n * `request.create_destination_connector.config.[azure_destination_connector_config_input]` **Added**\n * `response.config.[azure_destination_connector_config]` **Added**\n* `unstructured_client.destinations.get_destination()`: `response.config.[azure_destination_connector_config]` **Added**\n* `unstructured_client.destinations.list_destinations()`: \n * `request.destination_type` **Changed**\n * `response.[].config.[azure_destination_connector_config]` **Added**\n* `unstructured_client.destinations.update_destination()`: \n * `request.update_destination_connector.config.[azure_destination_connector_config_input]` **Added**\n * `response.config.[azure_destination_connector_config]` **Added**\n" diff --git a/.speakeasy/workflow.lock b/.speakeasy/workflow.lock index ca7f6466..e5c16830 100644 --- a/.speakeasy/workflow.lock +++ b/.speakeasy/workflow.lock @@ -1,21 +1,21 @@ -speakeasyVersion: 1.601.0 +speakeasyVersion: 1.615.2 sources: my-source: sourceNamespace: my-source - sourceRevisionDigest: sha256:8165f715321cd34bcebb6c9bb0734a1791777229937787b8e13707d519b05a5e - sourceBlobDigest: sha256:b4f8d9a6b0f4245c50b5e53298343df470978417248fa3988aeeb84ec9200c93 + sourceRevisionDigest: sha256:fa851bba6d6e224f6b8fd9e3f098ae1079b29ded25ce17ab72518540e9ee3902 + sourceBlobDigest: sha256:52c18b3b411c76e4f8dc5d2b852e3630d6401b3a8022e292a432c2ebe8d2c2b6 tags: - latest - - speakeasy-sdk-regen-1754698272 - - 1.1.45 + - speakeasy-sdk-regen-1756339855 + - 1.1.47 targets: unstructured-python: source: my-source sourceNamespace: my-source - sourceRevisionDigest: sha256:8165f715321cd34bcebb6c9bb0734a1791777229937787b8e13707d519b05a5e - sourceBlobDigest: sha256:b4f8d9a6b0f4245c50b5e53298343df470978417248fa3988aeeb84ec9200c93 + sourceRevisionDigest: sha256:fa851bba6d6e224f6b8fd9e3f098ae1079b29ded25ce17ab72518540e9ee3902 + sourceBlobDigest: sha256:52c18b3b411c76e4f8dc5d2b852e3630d6401b3a8022e292a432c2ebe8d2c2b6 codeSamplesNamespace: my-source-code-samples - codeSamplesRevisionDigest: sha256:a5e11972bfb15e43b7fcb2647b3a7b3e129e9303294f9110670280971b10780a + codeSamplesRevisionDigest: sha256:54f08520c48e4b706c8ffa67fd8c59940bad24add35b7159dea7f73042ff0e44 workflow: workflowVersion: 1.0.0 speakeasyVersion: latest diff --git a/RELEASES.md b/RELEASES.md index 562395d9..0e399fa2 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1119,4 +1119,14 @@ Based on: ### Generated - [python v0.42.3] . ### Releases -- [PyPI v0.42.3] https://pypi.org/project/unstructured-client/0.42.3 - . \ No newline at end of file +- [PyPI v0.42.3] https://pypi.org/project/unstructured-client/0.42.3 - . + +## 2025-09-15 00:10:40 +### Changes +Based on: +- OpenAPI Doc +- Speakeasy CLI 1.615.2 (2.698.4) https://github.com/speakeasy-api/speakeasy +### Generated +- [python v0.43.0] . +### Releases +- [PyPI v0.43.0] https://pypi.org/project/unstructured-client/0.43.0 - . \ No newline at end of file diff --git a/codeSamples.yaml b/codeSamples.yaml index f5eda8f2..b28551de 100644 --- a/codeSamples.yaml +++ b/codeSamples.yaml @@ -14,7 +14,7 @@ actions: "x-codeSamples": - "lang": "python" "label": "create_destination" - "source": "from unstructured_client import UnstructuredClient\nfrom unstructured_client.models import shared\n\n\nwith UnstructuredClient() as uc_client:\n\n res = uc_client.destinations.create_destination(request={\n \"create_destination_connector\": {\n \"name\": \"\",\n \"type\": shared.DestinationConnectorType.MOTHERDUCK,\n \"config\": {\n \"index_name\": \"\",\n \"api_key\": \"\",\n \"namespace\": \"\",\n \"batch_size\": 50,\n },\n },\n })\n\n assert res.destination_connector_information is not None\n\n # Handle response\n print(res.destination_connector_information)" + "source": "from unstructured_client import UnstructuredClient\nfrom unstructured_client.models import shared\n\n\nwith UnstructuredClient() as uc_client:\n\n res = uc_client.destinations.create_destination(request={\n \"create_destination_connector\": {\n \"name\": \"\",\n \"type\": shared.DestinationConnectorType.MONGODB,\n \"config\": {\n \"index_name\": \"\",\n \"api_key\": \"\",\n \"namespace\": \"\",\n \"batch_size\": 50,\n },\n },\n })\n\n assert res.destination_connector_information is not None\n\n # Handle response\n print(res.destination_connector_information)" - target: $["paths"]["/api/v1/destinations/{destination_id}"]["delete"] update: "x-codeSamples": @@ -32,7 +32,7 @@ actions: "x-codeSamples": - "lang": "python" "label": "update_destination" - "source": "from unstructured_client import UnstructuredClient\n\n\nwith UnstructuredClient() as uc_client:\n\n res = uc_client.destinations.update_destination(request={\n \"destination_id\": \"9726962d-9d1e-4f84-8787-c7313d183927\",\n \"update_destination_connector\": {\n \"config\": {\n \"bootstrap_servers\": \"\",\n \"port\": 9092,\n \"topic\": \"\",\n \"kafka_api_key\": \"\",\n \"secret\": \"\",\n \"batch_size\": 100,\n },\n },\n })\n\n assert res.destination_connector_information is not None\n\n # Handle response\n print(res.destination_connector_information)" + "source": "from unstructured_client import UnstructuredClient\n\n\nwith UnstructuredClient() as uc_client:\n\n res = uc_client.destinations.update_destination(request={\n \"destination_id\": \"962d9d1e-f847-487c-a731-3d18392716fb\",\n \"update_destination_connector\": {\n \"config\": {\n \"remote_url\": \"https://lined-clamp.info\",\n \"service_account_key\": \"\",\n },\n },\n })\n\n assert res.destination_connector_information is not None\n\n # Handle response\n print(res.destination_connector_information)" - target: $["paths"]["/api/v1/destinations/{destination_id}/connection-check"]["get"] update: "x-codeSamples": diff --git a/docs/models/shared/config.md b/docs/models/shared/config.md index 03abce7e..b6441eb9 100644 --- a/docs/models/shared/config.md +++ b/docs/models/shared/config.md @@ -3,6 +3,12 @@ ## Supported Types +### `shared.AzureDestinationConnectorConfigInput` + +```python +value: shared.AzureDestinationConnectorConfigInput = /* values here */ +``` + ### `shared.AstraDBConnectorConfigInput` ```python diff --git a/docs/models/shared/destinationconnectorinformationconfig.md b/docs/models/shared/destinationconnectorinformationconfig.md index f7871f5a..70b163e8 100644 --- a/docs/models/shared/destinationconnectorinformationconfig.md +++ b/docs/models/shared/destinationconnectorinformationconfig.md @@ -3,6 +3,12 @@ ## Supported Types +### `shared.AzureDestinationConnectorConfig` + +```python +value: shared.AzureDestinationConnectorConfig = /* values here */ +``` + ### `shared.AstraDBConnectorConfig` ```python diff --git a/docs/models/shared/destinationconnectortype.md b/docs/models/shared/destinationconnectortype.md index d0b8f5ab..02159f7f 100644 --- a/docs/models/shared/destinationconnectortype.md +++ b/docs/models/shared/destinationconnectortype.md @@ -5,6 +5,7 @@ | Name | Value | | -------------------------------- | -------------------------------- | +| `AZURE` | azure | | `ASTRADB` | astradb | | `AZURE_AI_SEARCH` | azure_ai_search | | `COUCHBASE` | couchbase | diff --git a/docs/models/shared/updatedestinationconnectorconfig.md b/docs/models/shared/updatedestinationconnectorconfig.md index a0424473..ea3688cb 100644 --- a/docs/models/shared/updatedestinationconnectorconfig.md +++ b/docs/models/shared/updatedestinationconnectorconfig.md @@ -3,6 +3,12 @@ ## Supported Types +### `shared.AzureDestinationConnectorConfigInput` + +```python +value: shared.AzureDestinationConnectorConfigInput = /* values here */ +``` + ### `shared.AstraDBConnectorConfigInput` ```python diff --git a/gen.yaml b/gen.yaml index 1060b902..50c8da68 100644 --- a/gen.yaml +++ b/gen.yaml @@ -13,12 +13,13 @@ generation: auth: oAuth2ClientCredentialsEnabled: false oAuth2PasswordEnabled: false + hoistGlobalSecurity: true tests: generateTests: true generateNewTests: false skipResponseBodyAssertions: false python: - version: 0.42.3 + version: 0.43.0 additionalDependencies: dev: deepdiff: '>=6.0' @@ -36,6 +37,9 @@ python: httpx: '>=0.27.0' pypdf: '>=4.0' requests-toolbelt: '>=1.0.0' + allowedRedefinedBuiltins: + - id + - object authors: - Unstructured baseErrorName: UnstructuredClientError @@ -69,4 +73,5 @@ python: pytestFilterWarnings: [] pytestTimeout: 0 responseFormat: envelope + sseFlatResponse: false templateVersion: v2 diff --git a/pyproject.toml b/pyproject.toml index 8684a295..a6675309 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "unstructured-client" -version = "0.42.3" +version = "0.43.0" description = "Python Client SDK for Unstructured API" authors = [{ name = "Unstructured" },] readme = "README-PYPI.md" @@ -49,6 +49,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/scripts/prepare_readme.py b/scripts/prepare_readme.py index 52e872a1..d75b47bc 100644 --- a/scripts/prepare_readme.py +++ b/scripts/prepare_readme.py @@ -10,12 +10,17 @@ GITHUB_URL = ( GITHUB_URL[: -len(".git")] if GITHUB_URL.endswith(".git") else GITHUB_URL ) + REPO_SUBDIR = "." + # 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/src/unstructured_client/_version.py b/src/unstructured_client/_version.py index a5be6a7b..c0cc746e 100644 --- a/src/unstructured_client/_version.py +++ b/src/unstructured_client/_version.py @@ -3,10 +3,10 @@ import importlib.metadata __title__: str = "unstructured-client" -__version__: str = "0.42.3" -__openapi_doc_version__: str = "1.1.45" -__gen_version__: str = "2.680.0" -__user_agent__: str = "speakeasy-sdk/python 0.42.3 2.680.0 1.1.45 unstructured-client" +__version__: str = "0.43.0" +__openapi_doc_version__: str = "1.1.47" +__gen_version__: str = "2.698.4" +__user_agent__: str = "speakeasy-sdk/python 0.43.0 2.698.4 1.1.47 unstructured-client" try: if __package__ is not None: diff --git a/src/unstructured_client/basesdk.py b/src/unstructured_client/basesdk.py index a1c0f684..d429490c 100644 --- a/src/unstructured_client/basesdk.py +++ b/src/unstructured_client/basesdk.py @@ -20,9 +20,19 @@ class BaseSDK: sdk_configuration: SDKConfiguration + parent_ref: Optional[object] = None + """ + Reference to the root SDK instance, if any. This will prevent it from + being garbage collected while there are active streams. + """ - def __init__(self, sdk_config: SDKConfiguration) -> None: + def __init__( + self, + sdk_config: SDKConfiguration, + parent_ref: Optional[object] = None, + ) -> None: self.sdk_configuration = sdk_config + self.parent_ref = parent_ref def _get_url(self, base_url, url_variables): sdk_url, sdk_variables = self.sdk_configuration.get_server_details() diff --git a/src/unstructured_client/models/errors/__init__.py b/src/unstructured_client/models/errors/__init__.py index 1aa6130f..c7c3b5d1 100644 --- a/src/unstructured_client/models/errors/__init__.py +++ b/src/unstructured_client/models/errors/__init__.py @@ -1,8 +1,10 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" +from .unstructuredclienterror import UnstructuredClientError from typing import TYPE_CHECKING from importlib import import_module import builtins +import sys if TYPE_CHECKING: from .httpvalidationerror import ( @@ -14,7 +16,6 @@ from .responsevalidationerror import ResponseValidationError from .sdkerror import SDKError from .servererror import ServerError, ServerErrorData - from .unstructuredclienterror import UnstructuredClientError __all__ = [ "Detail", @@ -37,10 +38,21 @@ "SDKError": ".sdkerror", "ServerError": ".servererror", "ServerErrorData": ".servererror", - "UnstructuredClientError": ".unstructuredclienterror", } +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: @@ -49,7 +61,7 @@ def __getattr__(attr_name: str) -> object: ) try: - module = import_module(module_name, __package__) + module = dynamic_import(module_name) result = getattr(module, attr_name) return result except ImportError as e: diff --git a/src/unstructured_client/models/errors/httpvalidationerror.py b/src/unstructured_client/models/errors/httpvalidationerror.py index 4be2ca24..97f9e47d 100644 --- a/src/unstructured_client/models/errors/httpvalidationerror.py +++ b/src/unstructured_client/models/errors/httpvalidationerror.py @@ -1,6 +1,7 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" from __future__ import annotations +from dataclasses import dataclass, field import httpx from typing import List, Optional, Union from typing_extensions import TypeAliasType @@ -23,8 +24,9 @@ class HTTPValidationErrorData(BaseModel): detail: Optional[Detail] = None +@dataclass(frozen=True) class HTTPValidationError(UnstructuredClientError): - data: HTTPValidationErrorData + data: HTTPValidationErrorData = field(hash=False) def __init__( self, @@ -34,4 +36,4 @@ def __init__( ): message = body or raw_response.text super().__init__(message, raw_response, body) - self.data = data + object.__setattr__(self, "data", data) diff --git a/src/unstructured_client/models/errors/no_response_error.py b/src/unstructured_client/models/errors/no_response_error.py index f98beea2..b710ea2b 100644 --- a/src/unstructured_client/models/errors/no_response_error.py +++ b/src/unstructured_client/models/errors/no_response_error.py @@ -1,12 +1,16 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" +from dataclasses import dataclass + + +@dataclass(frozen=True) class NoResponseError(Exception): """Error raised when no HTTP response is received from the server.""" message: str def __init__(self, message: str = "No response received"): - self.message = message + object.__setattr__(self, "message", message) super().__init__(message) def __str__(self): diff --git a/src/unstructured_client/models/errors/responsevalidationerror.py b/src/unstructured_client/models/errors/responsevalidationerror.py index c3c09737..99634229 100644 --- a/src/unstructured_client/models/errors/responsevalidationerror.py +++ b/src/unstructured_client/models/errors/responsevalidationerror.py @@ -2,10 +2,12 @@ import httpx from typing import Optional +from dataclasses import dataclass from unstructured_client.models.errors import UnstructuredClientError +@dataclass(frozen=True) class ResponseValidationError(UnstructuredClientError): """Error raised when there is a type mismatch between the response data and the expected Pydantic model.""" diff --git a/src/unstructured_client/models/errors/sdkerror.py b/src/unstructured_client/models/errors/sdkerror.py index 51e10405..52dc82cd 100644 --- a/src/unstructured_client/models/errors/sdkerror.py +++ b/src/unstructured_client/models/errors/sdkerror.py @@ -2,12 +2,14 @@ import httpx from typing import Optional +from dataclasses import dataclass from unstructured_client.models.errors import UnstructuredClientError MAX_MESSAGE_LEN = 10_000 +@dataclass(frozen=True) class SDKError(UnstructuredClientError): """The fallback error class if no more specific error class is matched.""" diff --git a/src/unstructured_client/models/errors/servererror.py b/src/unstructured_client/models/errors/servererror.py index 2b4c81a5..6b9412f5 100644 --- a/src/unstructured_client/models/errors/servererror.py +++ b/src/unstructured_client/models/errors/servererror.py @@ -1,6 +1,7 @@ """Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.""" from __future__ import annotations +from dataclasses import dataclass, field import httpx from typing import Optional from unstructured_client.models.errors import UnstructuredClientError @@ -11,8 +12,9 @@ class ServerErrorData(BaseModel): detail: Optional[str] = None +@dataclass(frozen=True) class ServerError(UnstructuredClientError): - data: ServerErrorData + data: ServerErrorData = field(hash=False) def __init__( self, @@ -22,4 +24,4 @@ def __init__( ): message = body or raw_response.text super().__init__(message, raw_response, body) - self.data = data + object.__setattr__(self, "data", data) diff --git a/src/unstructured_client/models/errors/unstructuredclienterror.py b/src/unstructured_client/models/errors/unstructuredclienterror.py index 054fb875..c37dbb62 100644 --- a/src/unstructured_client/models/errors/unstructuredclienterror.py +++ b/src/unstructured_client/models/errors/unstructuredclienterror.py @@ -2,25 +2,29 @@ import httpx from typing import Optional +from dataclasses import dataclass, field +@dataclass(frozen=True) class UnstructuredClientError(Exception): """The base class for all HTTP error responses.""" message: str status_code: int body: str - headers: httpx.Headers - raw_response: httpx.Response + headers: httpx.Headers = field(hash=False) + raw_response: httpx.Response = field(hash=False) def __init__( self, message: str, raw_response: httpx.Response, body: Optional[str] = None ): - self.message = message - self.status_code = raw_response.status_code - self.body = body if body is not None else raw_response.text - self.headers = raw_response.headers - self.raw_response = raw_response + object.__setattr__(self, "message", message) + object.__setattr__(self, "status_code", raw_response.status_code) + object.__setattr__( + self, "body", body if body is not None else raw_response.text + ) + object.__setattr__(self, "headers", raw_response.headers) + object.__setattr__(self, "raw_response", raw_response) def __str__(self): return self.message diff --git a/src/unstructured_client/models/operations/__init__.py b/src/unstructured_client/models/operations/__init__.py index 8c6fbfc2..1818438c 100644 --- a/src/unstructured_client/models/operations/__init__.py +++ b/src/unstructured_client/models/operations/__init__.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING from importlib import import_module import builtins +import sys if TYPE_CHECKING: from .cancel_job import ( @@ -391,6 +392,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: @@ -399,7 +412,7 @@ def __getattr__(attr_name: str) -> object: ) try: - module = import_module(module_name, __package__) + module = dynamic_import(module_name) result = getattr(module, attr_name) return result except ImportError as e: diff --git a/src/unstructured_client/models/shared/__init__.py b/src/unstructured_client/models/shared/__init__.py index 0ab9d4af..66073d1b 100644 --- a/src/unstructured_client/models/shared/__init__.py +++ b/src/unstructured_client/models/shared/__init__.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING from importlib import import_module import builtins +import sys if TYPE_CHECKING: from .astradbconnectorconfig import ( @@ -21,6 +22,14 @@ AzureAISearchConnectorConfigInput, AzureAISearchConnectorConfigInputTypedDict, ) + from .azuredestinationconnectorconfig import ( + AzureDestinationConnectorConfig, + AzureDestinationConnectorConfigTypedDict, + ) + from .azuredestinationconnectorconfiginput import ( + AzureDestinationConnectorConfigInput, + AzureDestinationConnectorConfigInputTypedDict, + ) from .azuresourceconnectorconfig import ( AzureSourceConnectorConfig, AzureSourceConnectorConfigTypedDict, @@ -413,6 +422,10 @@ "AzureAISearchConnectorConfigInput", "AzureAISearchConnectorConfigInputTypedDict", "AzureAISearchConnectorConfigTypedDict", + "AzureDestinationConnectorConfig", + "AzureDestinationConnectorConfigInput", + "AzureDestinationConnectorConfigInputTypedDict", + "AzureDestinationConnectorConfigTypedDict", "AzureSourceConnectorConfig", "AzureSourceConnectorConfigInput", "AzureSourceConnectorConfigInputTypedDict", @@ -654,6 +667,10 @@ "AzureAISearchConnectorConfigTypedDict": ".azureaisearchconnectorconfig", "AzureAISearchConnectorConfigInput": ".azureaisearchconnectorconfiginput", "AzureAISearchConnectorConfigInputTypedDict": ".azureaisearchconnectorconfiginput", + "AzureDestinationConnectorConfig": ".azuredestinationconnectorconfig", + "AzureDestinationConnectorConfigTypedDict": ".azuredestinationconnectorconfig", + "AzureDestinationConnectorConfigInput": ".azuredestinationconnectorconfiginput", + "AzureDestinationConnectorConfigInputTypedDict": ".azuredestinationconnectorconfiginput", "AzureSourceConnectorConfig": ".azuresourceconnectorconfig", "AzureSourceConnectorConfigTypedDict": ".azuresourceconnectorconfig", "AzureSourceConnectorConfigInput": ".azuresourceconnectorconfiginput", @@ -887,6 +904,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: @@ -895,7 +924,7 @@ def __getattr__(attr_name: str) -> object: ) try: - module = import_module(module_name, __package__) + module = dynamic_import(module_name) result = getattr(module, attr_name) return result except ImportError as e: diff --git a/src/unstructured_client/models/shared/createdestinationconnector.py b/src/unstructured_client/models/shared/createdestinationconnector.py index 3275fd05..f6b50154 100644 --- a/src/unstructured_client/models/shared/createdestinationconnector.py +++ b/src/unstructured_client/models/shared/createdestinationconnector.py @@ -9,6 +9,10 @@ AzureAISearchConnectorConfigInput, AzureAISearchConnectorConfigInputTypedDict, ) +from .azuredestinationconnectorconfiginput import ( + AzureDestinationConnectorConfigInput, + AzureDestinationConnectorConfigInputTypedDict, +) from .couchbasedestinationconnectorconfiginput import ( CouchbaseDestinationConnectorConfigInput, CouchbaseDestinationConnectorConfigInputTypedDict, @@ -98,20 +102,21 @@ Union[ GCSDestinationConnectorConfigInputTypedDict, ElasticsearchConnectorConfigInputTypedDict, + MongoDBConnectorConfigInputTypedDict, AzureAISearchConnectorConfigInputTypedDict, WeaviateDestinationConnectorConfigInputTypedDict, - MongoDBConnectorConfigInputTypedDict, DeltaTableConnectorConfigInputTypedDict, QdrantCloudDestinationConnectorConfigInputTypedDict, PineconeDestinationConnectorConfigInputTypedDict, + AzureDestinationConnectorConfigInputTypedDict, Neo4jDestinationConnectorConfigInputTypedDict, OneDriveDestinationConnectorConfigInputTypedDict, S3DestinationConnectorConfigInputTypedDict, AstraDBConnectorConfigInputTypedDict, PostgresDestinationConnectorConfigInputTypedDict, - DatabricksVolumesConnectorConfigInputTypedDict, MilvusDestinationConnectorConfigInputTypedDict, KafkaCloudDestinationConnectorConfigInputTypedDict, + DatabricksVolumesConnectorConfigInputTypedDict, CouchbaseDestinationConnectorConfigInputTypedDict, RedisDestinationConnectorConfigInputTypedDict, DatabricksVDTDestinationConnectorConfigInputTypedDict, @@ -127,20 +132,21 @@ Union[ GCSDestinationConnectorConfigInput, ElasticsearchConnectorConfigInput, + MongoDBConnectorConfigInput, AzureAISearchConnectorConfigInput, WeaviateDestinationConnectorConfigInput, - MongoDBConnectorConfigInput, DeltaTableConnectorConfigInput, QdrantCloudDestinationConnectorConfigInput, PineconeDestinationConnectorConfigInput, + AzureDestinationConnectorConfigInput, Neo4jDestinationConnectorConfigInput, OneDriveDestinationConnectorConfigInput, S3DestinationConnectorConfigInput, AstraDBConnectorConfigInput, PostgresDestinationConnectorConfigInput, - DatabricksVolumesConnectorConfigInput, MilvusDestinationConnectorConfigInput, KafkaCloudDestinationConnectorConfigInput, + DatabricksVolumesConnectorConfigInput, CouchbaseDestinationConnectorConfigInput, RedisDestinationConnectorConfigInput, DatabricksVDTDestinationConnectorConfigInput, diff --git a/src/unstructured_client/models/shared/destinationconnectorinformation.py b/src/unstructured_client/models/shared/destinationconnectorinformation.py index 0e912623..6c988b4e 100644 --- a/src/unstructured_client/models/shared/destinationconnectorinformation.py +++ b/src/unstructured_client/models/shared/destinationconnectorinformation.py @@ -9,6 +9,10 @@ AzureAISearchConnectorConfig, AzureAISearchConnectorConfigTypedDict, ) +from .azuredestinationconnectorconfig import ( + AzureDestinationConnectorConfig, + AzureDestinationConnectorConfigTypedDict, +) from .couchbasedestinationconnectorconfig import ( CouchbaseDestinationConnectorConfig, CouchbaseDestinationConnectorConfigTypedDict, @@ -106,20 +110,21 @@ Union[ GCSDestinationConnectorConfigTypedDict, ElasticsearchConnectorConfigTypedDict, + MongoDBConnectorConfigTypedDict, AzureAISearchConnectorConfigTypedDict, WeaviateDestinationConnectorConfigTypedDict, - MongoDBConnectorConfigTypedDict, DeltaTableConnectorConfigTypedDict, QdrantCloudDestinationConnectorConfigTypedDict, PineconeDestinationConnectorConfigTypedDict, + AzureDestinationConnectorConfigTypedDict, AstraDBConnectorConfigTypedDict, Neo4jDestinationConnectorConfigTypedDict, OneDriveDestinationConnectorConfigTypedDict, S3DestinationConnectorConfigTypedDict, PostgresDestinationConnectorConfigTypedDict, - DatabricksVolumesConnectorConfigTypedDict, MilvusDestinationConnectorConfigTypedDict, KafkaCloudDestinationConnectorConfigTypedDict, + DatabricksVolumesConnectorConfigTypedDict, CouchbaseDestinationConnectorConfigTypedDict, RedisDestinationConnectorConfigTypedDict, DatabricksVDTDestinationConnectorConfigTypedDict, @@ -135,20 +140,21 @@ Union[ GCSDestinationConnectorConfig, ElasticsearchConnectorConfig, + MongoDBConnectorConfig, AzureAISearchConnectorConfig, WeaviateDestinationConnectorConfig, - MongoDBConnectorConfig, DeltaTableConnectorConfig, QdrantCloudDestinationConnectorConfig, PineconeDestinationConnectorConfig, + AzureDestinationConnectorConfig, AstraDBConnectorConfig, Neo4jDestinationConnectorConfig, OneDriveDestinationConnectorConfig, S3DestinationConnectorConfig, PostgresDestinationConnectorConfig, - DatabricksVolumesConnectorConfig, MilvusDestinationConnectorConfig, KafkaCloudDestinationConnectorConfig, + DatabricksVolumesConnectorConfig, CouchbaseDestinationConnectorConfig, RedisDestinationConnectorConfig, DatabricksVDTDestinationConnectorConfig, diff --git a/src/unstructured_client/models/shared/destinationconnectortype.py b/src/unstructured_client/models/shared/destinationconnectortype.py index 6de4b97c..d463db75 100644 --- a/src/unstructured_client/models/shared/destinationconnectortype.py +++ b/src/unstructured_client/models/shared/destinationconnectortype.py @@ -6,6 +6,7 @@ class DestinationConnectorType(str, Enum, metaclass=utils.OpenEnumMeta): + AZURE = "azure" ASTRADB = "astradb" AZURE_AI_SEARCH = "azure_ai_search" COUCHBASE = "couchbase" diff --git a/src/unstructured_client/models/shared/updatedestinationconnector.py b/src/unstructured_client/models/shared/updatedestinationconnector.py index e10814f6..f4a189de 100644 --- a/src/unstructured_client/models/shared/updatedestinationconnector.py +++ b/src/unstructured_client/models/shared/updatedestinationconnector.py @@ -9,6 +9,10 @@ AzureAISearchConnectorConfigInput, AzureAISearchConnectorConfigInputTypedDict, ) +from .azuredestinationconnectorconfiginput import ( + AzureDestinationConnectorConfigInput, + AzureDestinationConnectorConfigInputTypedDict, +) from .couchbasedestinationconnectorconfiginput import ( CouchbaseDestinationConnectorConfigInput, CouchbaseDestinationConnectorConfigInputTypedDict, @@ -95,20 +99,21 @@ Union[ GCSDestinationConnectorConfigInputTypedDict, ElasticsearchConnectorConfigInputTypedDict, + MongoDBConnectorConfigInputTypedDict, AzureAISearchConnectorConfigInputTypedDict, WeaviateDestinationConnectorConfigInputTypedDict, - MongoDBConnectorConfigInputTypedDict, DeltaTableConnectorConfigInputTypedDict, QdrantCloudDestinationConnectorConfigInputTypedDict, PineconeDestinationConnectorConfigInputTypedDict, + AzureDestinationConnectorConfigInputTypedDict, Neo4jDestinationConnectorConfigInputTypedDict, OneDriveDestinationConnectorConfigInputTypedDict, S3DestinationConnectorConfigInputTypedDict, AstraDBConnectorConfigInputTypedDict, PostgresDestinationConnectorConfigInputTypedDict, - DatabricksVolumesConnectorConfigInputTypedDict, MilvusDestinationConnectorConfigInputTypedDict, KafkaCloudDestinationConnectorConfigInputTypedDict, + DatabricksVolumesConnectorConfigInputTypedDict, CouchbaseDestinationConnectorConfigInputTypedDict, RedisDestinationConnectorConfigInputTypedDict, DatabricksVDTDestinationConnectorConfigInputTypedDict, @@ -124,20 +129,21 @@ Union[ GCSDestinationConnectorConfigInput, ElasticsearchConnectorConfigInput, + MongoDBConnectorConfigInput, AzureAISearchConnectorConfigInput, WeaviateDestinationConnectorConfigInput, - MongoDBConnectorConfigInput, DeltaTableConnectorConfigInput, QdrantCloudDestinationConnectorConfigInput, PineconeDestinationConnectorConfigInput, + AzureDestinationConnectorConfigInput, Neo4jDestinationConnectorConfigInput, OneDriveDestinationConnectorConfigInput, S3DestinationConnectorConfigInput, AstraDBConnectorConfigInput, PostgresDestinationConnectorConfigInput, - DatabricksVolumesConnectorConfigInput, MilvusDestinationConnectorConfigInput, KafkaCloudDestinationConnectorConfigInput, + DatabricksVolumesConnectorConfigInput, CouchbaseDestinationConnectorConfigInput, RedisDestinationConnectorConfigInput, DatabricksVDTDestinationConnectorConfigInput, diff --git a/src/unstructured_client/sdk.py b/src/unstructured_client/sdk.py index 014bb146..117ad32b 100644 --- a/src/unstructured_client/sdk.py +++ b/src/unstructured_client/sdk.py @@ -7,6 +7,7 @@ from .utils.retries import RetryConfig import httpx import importlib +import sys from typing import Any, Callable, Dict, Optional, TYPE_CHECKING, Union, cast from unstructured_client import utils from unstructured_client._hooks import SDKHooks @@ -107,6 +108,7 @@ def __init__( timeout_ms=timeout_ms, debug_logger=debug_logger, ), + parent_ref=self, ) hooks = SDKHooks() @@ -131,13 +133,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/src/unstructured_client/utils/__init__.py b/src/unstructured_client/utils/__init__.py index dc88403b..56164cf3 100644 --- a/src/unstructured_client/utils/__init__.py +++ b/src/unstructured_client/utils/__init__.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING from importlib import import_module import builtins +import sys if TYPE_CHECKING: from .annotations import get_discriminator @@ -159,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: @@ -167,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}" diff --git a/src/unstructured_client/utils/eventstreaming.py b/src/unstructured_client/utils/eventstreaming.py index 74a63f75..0969899b 100644 --- a/src/unstructured_client/utils/eventstreaming.py +++ b/src/unstructured_client/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