diff --git a/airbyte/_util/api_duck_types.py b/airbyte/_util/api_duck_types.py index fe0a8c205..4f1dbd812 100644 --- a/airbyte/_util/api_duck_types.py +++ b/airbyte/_util/api_duck_types.py @@ -7,7 +7,7 @@ if TYPE_CHECKING: - import requests + import httpx class AirbyteApiResponseDuckType(Protocol): @@ -17,5 +17,5 @@ class AirbyteApiResponseDuckType(Protocol): r"""HTTP response content type for this operation""" status_code: int r"""HTTP response status code for this operation""" - raw_response: requests.Response + raw_response: httpx.Response r"""Raw HTTP response; suitable for custom response parsing""" diff --git a/airbyte/_util/api_util.py b/airbyte/_util/api_util.py index e3f0a9eb5..636f24b36 100644 --- a/airbyte/_util/api_util.py +++ b/airbyte/_util/api_util.py @@ -265,7 +265,7 @@ def get_workspace( base_context = {"workspace_id": workspace_id, "api_root": api_root} try: response = airbyte_instance.workspaces.get_workspace( - api.GetWorkspaceRequest( + request=api.GetWorkspaceRequest( workspace_id=workspace_id, ), ) @@ -356,7 +356,7 @@ def rename_workspace( } try: response = airbyte_instance.workspaces.update_workspace( - api.UpdateWorkspaceRequest( + request=api.UpdateWorkspaceRequest( workspace_id=workspace_id, workspace_update_request=models.WorkspaceUpdateRequest(name=name), ) @@ -456,7 +456,7 @@ def permanently_delete_workspace( } try: response = airbyte_instance.workspaces.delete_workspace( - api.DeleteWorkspaceRequest(workspace_id=workspace_id), + request=api.DeleteWorkspaceRequest(workspace_id=workspace_id), ) except SDKError as e: raise _wrap_sdk_error(e, base_context) from e @@ -505,7 +505,7 @@ def list_connections( while remaining is None or remaining > 0: try: response = airbyte_instance.connections.list_connections( - api.ListConnectionsRequest( + request=api.ListConnectionsRequest( workspace_ids=[workspace_id], offset=current_offset, limit=PAGE_SIZE, @@ -576,7 +576,7 @@ def list_workspaces( page_limit = PAGE_SIZE if has_name_filter else _get_page_limit(remaining) try: response: api.ListWorkspacesResponse = airbyte_instance.workspaces.list_workspaces( - api.ListWorkspacesRequest( + request=api.ListWorkspacesRequest( offset=current_offset, limit=page_limit, ), @@ -643,7 +643,7 @@ def list_sources( while remaining is None or remaining > 0: try: response: api.ListSourcesResponse = airbyte_instance.sources.list_sources( - api.ListSourcesRequest( + request=api.ListSourcesRequest( workspace_ids=[workspace_id], offset=current_offset, limit=PAGE_SIZE, @@ -710,7 +710,7 @@ def list_destinations( while remaining is None or remaining > 0: try: response = airbyte_instance.destinations.list_destinations( - api.ListDestinationsRequest( + request=api.ListDestinationsRequest( workspace_ids=[workspace_id], offset=current_offset, limit=PAGE_SIZE, @@ -777,7 +777,7 @@ def get_connection( } try: response = airbyte_instance.connections.get_connection( - api.GetConnectionRequest( + request=api.GetConnectionRequest( connection_id=connection_id, ), ) @@ -821,7 +821,7 @@ def run_connection( api_root=api_root, ) response = airbyte_instance.jobs.create_job( - models.JobCreateRequest( + request=models.JobCreateRequest( connection_id=connection_id, job_type=models.JobTypeEnum.SYNC, ), @@ -908,7 +908,7 @@ def get_job_logs( # noqa: PLR0913 # Too many arguments - needed for auth flexi page_limit = _get_page_limit(remaining) try: response: api.ListJobsResponse = airbyte_instance.jobs.list_jobs( - api.ListJobsRequest( + request=api.ListJobsRequest( workspace_ids=[workspace_id], connection_id=connection_id, limit=page_limit, @@ -982,7 +982,7 @@ def get_job_info( api_root=api_root, ) response = airbyte_instance.jobs.get_job( - api.GetJobRequest( + request=api.GetJobRequest( job_id=job_id, ), ) @@ -1025,7 +1025,7 @@ def create_source( api_root=api_root, ) response: api.CreateSourceResponse = airbyte_instance.sources.create_source( - models.SourceCreateRequest( + request=models.SourceCreateRequest( name=name, workspace_id=workspace_id, configuration=config, # Speakeasy API wants a dataclass, not a dict @@ -1062,7 +1062,7 @@ def get_source( api_root=api_root, ) response = airbyte_instance.sources.get_source( - api.GetSourceRequest( + request=api.GetSourceRequest( source_id=source_id, ), ) @@ -1144,7 +1144,7 @@ def delete_source( api_root=api_root, ) response = airbyte_instance.sources.delete_source( - api.DeleteSourceRequest( + request=api.DeleteSourceRequest( source_id=source_id, ), ) @@ -1192,7 +1192,7 @@ def patch_source( api_root=api_root, ) response = airbyte_instance.sources.patch_source( - api.PatchSourceRequest( + request=api.PatchSourceRequest( source_id=source_id, source_patch_request=models.SourcePatchRequest( name=name, @@ -1262,7 +1262,7 @@ def create_destination( # https://github.com/airbytehq/PyAirbyte/issues/743 definition_id_override = "a7bcc9d8-13b3-4e49-b80d-d020b90045e3" response: api.CreateDestinationResponse = airbyte_instance.destinations.create_destination( - models.DestinationCreateRequest( + request=models.DestinationCreateRequest( definition_id=definition_id_override, name=name, workspace_id=workspace_id, @@ -1298,7 +1298,7 @@ def get_destination( api_root=api_root, ) response = airbyte_instance.destinations.get_destination( - api.GetDestinationRequest( + request=api.GetDestinationRequest( destination_id=destination_id, ), ) @@ -1399,7 +1399,7 @@ def delete_destination( api_root=api_root, ) response = airbyte_instance.destinations.delete_destination( - api.DeleteDestinationRequest( + request=api.DeleteDestinationRequest( destination_id=destination_id, ), ) @@ -1447,7 +1447,7 @@ def patch_destination( api_root=api_root, ) response = airbyte_instance.destinations.patch_destination( - api.PatchDestinationRequest( + request=api.PatchDestinationRequest( destination_id=destination_id, destination_patch_request=models.DestinationPatchRequest( name=name, @@ -1525,7 +1525,7 @@ def create_connection( # noqa: PLR0913 # Too many arguments ) stream_configurations_obj = build_stream_configurations(selected_stream_names) response = airbyte_instance.connections.create_connection( - models.ConnectionCreateRequest( + request=models.ConnectionCreateRequest( name=name, source_id=source_id, destination_id=destination_id, @@ -1663,7 +1663,7 @@ def delete_connection( api_root=api_root, ) response = airbyte_instance.connections.delete_connection( - api.DeleteConnectionRequest( + request=api.DeleteConnectionRequest( connection_id=connection_id, ), ) @@ -1731,7 +1731,7 @@ def patch_connection( # noqa: PLR0913 # Too many arguments status_value = status response = airbyte_instance.connections.patch_connection( - api.PatchConnectionRequest( + request=api.PatchConnectionRequest( connection_id=connection_id, connection_patch_request=models.ConnectionPatchRequest( name=name, @@ -1960,7 +1960,7 @@ def create_custom_yaml_source_definition( create_declarative_source_definition_request=request_body, ) response = airbyte_instance.declarative_source_definitions.create_declarative_source_definition( - request + request=request ) if response.declarative_source_definition_response is None: raise AirbyteError( @@ -1990,7 +1990,7 @@ def list_custom_yaml_source_definitions( workspace_id=workspace_id, ) response = airbyte_instance.declarative_source_definitions.list_declarative_source_definitions( - request + request=request ) if ( not status_ok(response.status_code) @@ -2029,7 +2029,7 @@ def get_custom_yaml_source_definition( definition_id=definition_id, ) response = airbyte_instance.declarative_source_definitions.get_declarative_source_definition( - request + request=request ) if ( not status_ok(response.status_code) @@ -2074,7 +2074,7 @@ def update_custom_yaml_source_definition( update_declarative_source_definition_request=request_body, ) response = airbyte_instance.declarative_source_definitions.update_declarative_source_definition( - request + request=request ) if ( not status_ok(response.status_code) @@ -2160,7 +2160,7 @@ def delete_custom_yaml_source_definition( definition_id=definition_id, ) response = airbyte_instance.declarative_source_definitions.delete_declarative_source_definition( - request + request=request ) if not status_ok(response.status_code): raise AirbyteError( diff --git a/airbyte/caches/_utils/_cache_to_dest.py b/airbyte/caches/_utils/_cache_to_dest.py index 2826d92e2..e260238d4 100644 --- a/airbyte/caches/_utils/_cache_to_dest.py +++ b/airbyte/caches/_utils/_cache_to_dest.py @@ -13,7 +13,9 @@ DestinationDuckdb, DestinationPostgres, DestinationSnowflake, - UsernameAndPassword, +) +from airbyte_api.models import ( + DestinationSnowflakeUsernameAndPassword as UsernameAndPassword, ) from airbyte.secrets.base import SecretString diff --git a/pyproject.toml b/pyproject.toml index 276d7fa53..f4085c762 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ authors = [ requires-python = ">=3.10,<3.13" dynamic = ["version"] dependencies = [ - "airbyte-api>=0.53.0,<1.0", + "airbyte-api==1.0.1", "airbyte-cdk>=7.21.1,<8.0.0", "airbyte-protocol-models-pdv2>=0.13.0,<1.0", "cryptography>=44.0.0,<47.0.0,!=45.0.0,!=45.0.1", # 45.0.0/45.0.1 broke load_pem_private_key() diff --git a/tests/unit_tests/test_cloud_api_util.py b/tests/unit_tests/test_cloud_api_util.py index a0335c5a2..f402e8615 100644 --- a/tests/unit_tests/test_cloud_api_util.py +++ b/tests/unit_tests/test_cloud_api_util.py @@ -6,7 +6,7 @@ from types import SimpleNamespace import pytest -import requests +import httpx from airbyte._util import api_util from airbyte.exceptions import AirbyteWorkspaceNotEmptyError, PyAirbyteInputError from airbyte.secrets.base import SecretString @@ -30,8 +30,9 @@ def _list_jobs_response( next_page: str | None, ) -> api.ListJobsResponse: """Create a paginated jobs API response.""" - raw_response = requests.Response() - raw_response.url = "https://api.airbyte.com/v1/jobs" + raw_response = httpx.Response( + 200, request=httpx.Request("GET", "https://api.airbyte.com/v1/jobs") + ) return api.ListJobsResponse( content_type="application/json", status_code=200, @@ -51,7 +52,9 @@ def _connection_response(name: str, index: int) -> models.ConnectionResponse: created_at=index, destination_id=f"destination-{index}", name=name, - schedule={}, + schedule=models.ConnectionScheduleResponse( + schedule_type=models.ScheduleTypeWithBasicEnum.MANUAL, + ), source_id=f"source-{index}", status=models.ConnectionStatusEnum.ACTIVE, tags=[], @@ -75,8 +78,9 @@ def _list_connections_response( next_page: str | None, ) -> api.ListConnectionsResponse: """Create a paginated connections API response.""" - raw_response = requests.Response() - raw_response.url = "https://api.airbyte.com/v1/connections" + raw_response = httpx.Response( + 200, request=httpx.Request("GET", "https://api.airbyte.com/v1/connections") + ) return api.ListConnectionsResponse( content_type="application/json", status_code=200, @@ -94,8 +98,9 @@ def _list_workspaces_response( next_page: str | None, ) -> api.ListWorkspacesResponse: """Create a paginated workspaces API response.""" - raw_response = requests.Response() - raw_response.url = "https://api.airbyte.com/v1/workspaces" + raw_response = httpx.Response( + 200, request=httpx.Request("GET", "https://api.airbyte.com/v1/workspaces") + ) return api.ListWorkspacesResponse( content_type="application/json", status_code=200, @@ -118,8 +123,9 @@ def create_workspace( ) -> api.CreateWorkspaceResponse: nonlocal captured_request captured_request = request - raw_response = requests.Response() - raw_response.url = "https://api.airbyte.com/v1/workspaces" + raw_response = httpx.Response( + 200, request=httpx.Request("GET", "https://api.airbyte.com/v1/workspaces") + ) return api.CreateWorkspaceResponse( content_type="application/json", status_code=200, @@ -163,8 +169,12 @@ def update_workspace( ) -> api.UpdateWorkspaceResponse: nonlocal captured_request captured_request = request - raw_response = requests.Response() - raw_response.url = "https://api.airbyte.com/v1/workspaces/workspace-1" + raw_response = httpx.Response( + 200, + request=httpx.Request( + "GET", "https://api.airbyte.com/v1/workspaces/workspace-1" + ), + ) return api.UpdateWorkspaceResponse( content_type="application/json", status_code=200, @@ -207,8 +217,12 @@ def patch_connection( ) -> api.PatchConnectionResponse: nonlocal captured_request captured_request = request - raw_response = requests.Response() - raw_response.url = "https://api.airbyte.com/v1/connections/connection-1" + raw_response = httpx.Response( + 200, + request=httpx.Request( + "GET", "https://api.airbyte.com/v1/connections/connection-1" + ), + ) return api.PatchConnectionResponse( content_type="application/json", status_code=200, @@ -292,8 +306,12 @@ def delete_workspace( nonlocal delete_calls delete_calls += 1 assert request.workspace_id == "workspace-1" - raw_response = requests.Response() - raw_response.url = "https://api.airbyte.com/v1/workspaces/workspace-1" + raw_response = httpx.Response( + 204, + request=httpx.Request( + "DELETE", "https://api.airbyte.com/v1/workspaces/workspace-1" + ), + ) return api.DeleteWorkspaceResponse( content_type="", status_code=204, @@ -342,8 +360,12 @@ def delete_workspace( ) -> api.DeleteWorkspaceResponse: nonlocal delete_calls delete_calls += 1 - raw_response = requests.Response() - raw_response.url = "https://api.airbyte.com/v1/workspaces/workspace-1" + raw_response = httpx.Response( + 204, + request=httpx.Request( + "DELETE", "https://api.airbyte.com/v1/workspaces/workspace-1" + ), + ) return api.DeleteWorkspaceResponse( content_type="", status_code=204, diff --git a/uv.lock b/uv.lock index 5b5305d6d..ba4295bfd 100644 --- a/uv.lock +++ b/uv.lock @@ -192,7 +192,7 @@ dev = [ [package.metadata] requires-dist = [ - { name = "airbyte-api", specifier = ">=0.53.0,<1.0" }, + { name = "airbyte-api", specifier = "==1.0.1" }, { name = "airbyte-cdk", specifier = ">=7.21.1,<8.0.0" }, { name = "airbyte-protocol-models-pdv2", specifier = ">=0.13.0,<1.0" }, { name = "cryptography", specifier = ">=44.0.0,!=45.0.0,!=45.0.1,<47.0.0" }, @@ -258,27 +258,16 @@ dev = [ [[package]] name = "airbyte-api" -version = "0.53.0" +version = "1.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "dataclasses-json" }, - { name = "idna" }, - { name = "jsonpath-python" }, - { name = "marshmallow" }, - { name = "mypy-extensions" }, - { name = "packaging" }, - { name = "python-dateutil" }, - { name = "requests" }, - { name = "six" }, - { name = "typing-extensions" }, - { name = "typing-inspect" }, - { name = "urllib3" }, + { name = "httpcore" }, + { name = "httpx" }, + { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/23/8debf9c4ca8652c9ceb60b8074e654191ba2053001616151993b39d6cdcb/airbyte-api-0.53.0.tar.gz", hash = "sha256:f054ed170f9a691c3304e93a5212670fd2a38e5debb667c72d5ef8eb89cf7e9d", size = 330090, upload-time = "2025-10-02T19:55:43.378Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/94/9dee92bac34428e28e403f0863e1fd2db14450dc72ad9a58294c94af71e4/airbyte_api-1.0.1.tar.gz", hash = "sha256:4c40e49b94a62b21836aea126d373365e1002b424022c8e7e262fd0a3d7a4fc6", size = 500468, upload-time = "2026-06-23T07:02:39.109Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/f5/ca44b6f3919f049a4441755958c042fcea09a44e876352a6005f5e5a9e46/airbyte_api-0.53.0-py3-none-any.whl", hash = "sha256:0bd86d5122789a7c97115a4b52ce492b013d0ea8eeab597b6495b0b310332f28", size = 773825, upload-time = "2025-10-02T19:55:42.043Z" }, + { url = "https://files.pythonhosted.org/packages/24/fa/472753b8a2d38264a1643c27f10bd0b4d0a38f4912918ee943b1e69c7ea7/airbyte_api-1.0.1-py3-none-any.whl", hash = "sha256:edaad71bb9ed123f15cf9f91f78704b88d449584c734b14c4ec8c13ad435516f", size = 1060335, upload-time = "2026-06-23T07:02:37.503Z" }, ] [[package]] @@ -841,19 +830,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/12/a3/2e00fececc34a99ae3a5d5702a5dd29c5371e4ed016647301a2b9bcc1976/cyclopts-4.5.0-py3-none-any.whl", hash = "sha256:305b9aa90a9cd0916f0a450b43e50ad5df9c252680731a0719edfb9b20381bf5", size = 199772, upload-time = "2026-01-16T02:07:14.707Z" }, ] -[[package]] -name = "dataclasses-json" -version = "0.6.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "marshmallow" }, - { name = "typing-inspect" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/64/a4/f71d9cf3a5ac257c993b5ca3f93df5f7fb395c725e7f1e6479d2514173c3/dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0", size = 32227, upload-time = "2024-06-09T16:20:19.103Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686, upload-time = "2024-06-09T16:20:16.715Z" }, -] - [[package]] name = "dateparser" version = "1.2.2" @@ -1817,15 +1793,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" }, ] -[[package]] -name = "jsonpath-python" -version = "1.1.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b8/bf/626a72f2d093c5eb4f4de55b443714afa7231beeae40d4a1c69b5c5aa4d1/jsonpath_python-1.1.4.tar.gz", hash = "sha256:bb3e13854e4807c078a1503ae2d87c211b8bff4d9b40b6455ed583b3b50a7fdd", size = 84766, upload-time = "2025-11-25T12:08:39.521Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/bc/52e5bf0d9839e082b976c19afcab7561d0d719c7627483bf5dc251d27eed/jsonpath_python-1.1.4-py3-none-any.whl", hash = "sha256:8700cb8610c44da6e5e9bff50232779c44bf7dc5bc62662d49319ee746898442", size = 12687, upload-time = "2025-11-25T12:08:38.453Z" }, -] - [[package]] name = "jsonref" version = "1.1.0" @@ -1990,18 +1957,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, ] -[[package]] -name = "marshmallow" -version = "3.26.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/55/79/de6c16cc902f4fc372236926b0ce2ab7845268dcc30fb2fbb7f71b418631/marshmallow-3.26.2.tar.gz", hash = "sha256:bbe2adb5a03e6e3571b573f42527c6fe926e17467833660bebd11593ab8dfd57", size = 222095, upload-time = "2025-12-22T06:53:53.309Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/be/2f/5108cb3ee4ba6501748c4908b908e55f42a5b66245b4cfe0c99326e1ef6e/marshmallow-3.26.2-py3-none-any.whl", hash = "sha256:013fa8a3c4c276c24d26d84ce934dc964e2aa794345a0f8c7e5a7191482c8a73", size = 50964, upload-time = "2025-12-22T06:53:51.801Z" }, -] - [[package]] name = "mcp" version = "1.25.0" @@ -2129,15 +2084,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, ] -[[package]] -name = "mypy-extensions" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, -] - [[package]] name = "nexus-rpc" version = "1.2.0" @@ -4151,19 +4097,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] -[[package]] -name = "typing-inspect" -version = "0.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mypy-extensions" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825, upload-time = "2023-05-24T20:25:47.612Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827, upload-time = "2023-05-24T20:25:45.287Z" }, -] - [[package]] name = "typing-inspection" version = "0.4.2"