From f6c9ee8b1713fee3b65a599c98653d6183d6e162 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 2 Jan 2026 16:07:57 +0000 Subject: [PATCH 01/18] chore(internal/tests): avoid race condition with implicit client cleanup --- tests/test_client.py | 366 ++++++++++++++++++++++++------------------- 1 file changed, 202 insertions(+), 164 deletions(-) diff --git a/tests/test_client.py b/tests/test_client.py index 7b21288..feeeacf 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -60,51 +60,49 @@ def _get_open_connections(client: OnebusawaySDK | AsyncOnebusawaySDK) -> int: class TestOnebusawaySDK: - client = OnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=True) - @pytest.mark.respx(base_url=base_url) - def test_raw_response(self, respx_mock: MockRouter) -> None: + def test_raw_response(self, respx_mock: MockRouter, client: OnebusawaySDK) -> None: respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.post("/foo", cast_to=httpx.Response) + response = client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} @pytest.mark.respx(base_url=base_url) - def test_raw_response_for_binary(self, respx_mock: MockRouter) -> None: + def test_raw_response_for_binary(self, respx_mock: MockRouter, client: OnebusawaySDK) -> None: respx_mock.post("/foo").mock( return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') ) - response = self.client.post("/foo", cast_to=httpx.Response) + response = client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} - def test_copy(self) -> None: - copied = self.client.copy() - assert id(copied) != id(self.client) + def test_copy(self, client: OnebusawaySDK) -> None: + copied = client.copy() + assert id(copied) != id(client) - copied = self.client.copy(api_key="another My API Key") + copied = client.copy(api_key="another My API Key") assert copied.api_key == "another My API Key" - assert self.client.api_key == "My API Key" + assert client.api_key == "My API Key" - def test_copy_default_options(self) -> None: + def test_copy_default_options(self, client: OnebusawaySDK) -> None: # options that have a default are overridden correctly - copied = self.client.copy(max_retries=7) + copied = client.copy(max_retries=7) assert copied.max_retries == 7 - assert self.client.max_retries == 2 + assert client.max_retries == 2 copied2 = copied.copy(max_retries=6) assert copied2.max_retries == 6 assert copied.max_retries == 7 # timeout - assert isinstance(self.client.timeout, httpx.Timeout) - copied = self.client.copy(timeout=None) + assert isinstance(client.timeout, httpx.Timeout) + copied = client.copy(timeout=None) assert copied.timeout is None - assert isinstance(self.client.timeout, httpx.Timeout) + assert isinstance(client.timeout, httpx.Timeout) def test_copy_default_headers(self) -> None: client = OnebusawaySDK( @@ -139,6 +137,7 @@ def test_copy_default_headers(self) -> None: match="`default_headers` and `set_default_headers` arguments are mutually exclusive", ): client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + client.close() def test_copy_default_query(self) -> None: client = OnebusawaySDK( @@ -176,13 +175,15 @@ def test_copy_default_query(self) -> None: ): client.copy(set_default_query={}, default_query={"foo": "Bar", "key": api_key}) - def test_copy_signature(self) -> None: + client.close() + + def test_copy_signature(self, client: OnebusawaySDK) -> None: # ensure the same parameters that can be passed to the client are defined in the `.copy()` method init_signature = inspect.signature( # mypy doesn't like that we access the `__init__` property. - self.client.__init__, # type: ignore[misc] + client.__init__, # type: ignore[misc] ) - copy_signature = inspect.signature(self.client.copy) + copy_signature = inspect.signature(client.copy) exclude_params = {"transport", "proxies", "_strict_response_validation"} for name in init_signature.parameters.keys(): @@ -193,12 +194,12 @@ def test_copy_signature(self) -> None: assert copy_param is not None, f"copy() signature is missing the {name} param" @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") - def test_copy_build_request(self) -> None: + def test_copy_build_request(self, client: OnebusawaySDK) -> None: options = FinalRequestOptions(method="get", url="/foo") def build_request(options: FinalRequestOptions) -> None: - client = self.client.copy() - client._build_request(options) + client_copy = client.copy() + client_copy._build_request(options) # ensure that the machinery is warmed up before tracing starts. build_request(options) @@ -255,14 +256,12 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic print(frame) raise AssertionError() - def test_request_timeout(self) -> None: - request = self.client._build_request(FinalRequestOptions(method="get", url="/foo")) + def test_request_timeout(self, client: OnebusawaySDK) -> None: + request = client._build_request(FinalRequestOptions(method="get", url="/foo")) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT - request = self.client._build_request( - FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) - ) + request = client._build_request(FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0))) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(100.0) @@ -275,6 +274,8 @@ def test_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(0) + client.close() + def test_http_client_timeout_option(self) -> None: # custom timeout given to the httpx client should be used with httpx.Client(timeout=None) as http_client: @@ -286,6 +287,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(None) + client.close() + # no timeout given to the httpx client should not use the httpx default with httpx.Client() as http_client: client = OnebusawaySDK( @@ -296,6 +299,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT + client.close() + # explicitly passing the default timeout currently results in it being ignored with httpx.Client(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: client = OnebusawaySDK( @@ -306,6 +311,8 @@ def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT # our default + client.close() + async def test_invalid_http_client(self) -> None: with pytest.raises(TypeError, match="Invalid `http_client` arg"): async with httpx.AsyncClient() as http_client: @@ -317,14 +324,14 @@ async def test_invalid_http_client(self) -> None: ) def test_default_headers_option(self) -> None: - client = OnebusawaySDK( + test_client = OnebusawaySDK( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} ) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "bar" assert request.headers.get("x-stainless-lang") == "python" - client2 = OnebusawaySDK( + test_client2 = OnebusawaySDK( base_url=base_url, api_key=api_key, _strict_response_validation=True, @@ -333,10 +340,13 @@ def test_default_headers_option(self) -> None: "X-Stainless-Lang": "my-overriding-header", }, ) - request = client2._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "stainless" assert request.headers.get("x-stainless-lang") == "my-overriding-header" + test_client.close() + test_client2.close() + def test_default_query_option(self) -> None: client = OnebusawaySDK( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} @@ -355,8 +365,10 @@ def test_default_query_option(self) -> None: url = httpx.URL(request.url) assert dict(url.params) == {"foo": "baz", "query_param": "overridden", "key": api_key} - def test_request_extra_json(self) -> None: - request = self.client._build_request( + client.close() + + def test_request_extra_json(self, client: OnebusawaySDK) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -367,7 +379,7 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": False} - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -378,7 +390,7 @@ def test_request_extra_json(self) -> None: assert data == {"baz": False} # `extra_json` takes priority over `json_data` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -389,8 +401,8 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": None} - def test_request_extra_headers(self) -> None: - request = self.client._build_request( + def test_request_extra_headers(self, client: OnebusawaySDK) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -400,7 +412,7 @@ def test_request_extra_headers(self) -> None: assert request.headers.get("X-Foo") == "Foo" # `extra_headers` takes priority over `default_headers` when keys clash - request = self.client.with_options(default_headers={"X-Bar": "true"})._build_request( + request = client.with_options(default_headers={"X-Bar": "true"})._build_request( FinalRequestOptions( method="post", url="/foo", @@ -411,8 +423,8 @@ def test_request_extra_headers(self) -> None: ) assert request.headers.get("X-Bar") == "false" - def test_request_extra_query(self) -> None: - request = self.client._build_request( + def test_request_extra_query(self, client: OnebusawaySDK) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -425,7 +437,7 @@ def test_request_extra_query(self) -> None: assert params == {"my_query_param": "Foo", "key": api_key} # if both `query` and `extra_query` are given, they are merged - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -439,7 +451,7 @@ def test_request_extra_query(self) -> None: assert params == {"bar": "1", "foo": "2", "key": api_key} # `extra_query` takes priority over `query` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -482,7 +494,7 @@ def test_multipart_repeating_array(self, client: OnebusawaySDK) -> None: ] @pytest.mark.respx(base_url=base_url) - def test_basic_union_response(self, respx_mock: MockRouter) -> None: + def test_basic_union_response(self, respx_mock: MockRouter, client: OnebusawaySDK) -> None: class Model1(BaseModel): name: str @@ -491,12 +503,12 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" @pytest.mark.respx(base_url=base_url) - def test_union_response_different_types(self, respx_mock: MockRouter) -> None: + def test_union_response_different_types(self, respx_mock: MockRouter, client: OnebusawaySDK) -> None: """Union of objects with the same field name using a different type""" class Model1(BaseModel): @@ -507,18 +519,20 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) - response = self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model1) assert response.foo == 1 @pytest.mark.respx(base_url=base_url) - def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter) -> None: + def test_non_application_json_content_type_for_json_data( + self, respx_mock: MockRouter, client: OnebusawaySDK + ) -> None: """ Response that sets Content-Type to something other than application/json but returns json data """ @@ -534,7 +548,7 @@ class Model(BaseModel): ) ) - response = self.client.get("/foo", cast_to=Model) + response = client.get("/foo", cast_to=Model) assert isinstance(response, Model) assert response.foo == 2 @@ -548,6 +562,8 @@ def test_base_url_setter(self) -> None: assert client.base_url == "https://example.com/from_setter/" + client.close() + def test_base_url_env(self) -> None: with update_env(ONEBUSAWAY_SDK_BASE_URL="http://localhost:5000/from/env"): client = OnebusawaySDK(api_key=api_key, _strict_response_validation=True) @@ -578,6 +594,7 @@ def test_base_url_trailing_slash(self, client: OnebusawaySDK) -> None: ) expected_url = f"http://localhost:5000/custom/path/foo?key={urllib.parse.quote_plus(client.api_key)}" assert request.url == expected_url + client.close() @pytest.mark.parametrize( "client", @@ -604,6 +621,7 @@ def test_base_url_no_trailing_slash(self, client: OnebusawaySDK) -> None: ) expected_url = f"http://localhost:5000/custom/path/foo?key={urllib.parse.quote_plus(client.api_key)}" assert request.url == expected_url + client.close() @pytest.mark.parametrize( "client", @@ -630,35 +648,36 @@ def test_absolute_request_url(self, client: OnebusawaySDK) -> None: ) expected_url = f"https://myapi.com/foo?key={urllib.parse.quote_plus(client.api_key)}" assert request.url == expected_url + client.close() def test_copied_client_does_not_close_http(self) -> None: - client = OnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=True) - assert not client.is_closed() + test_client = OnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=True) + assert not test_client.is_closed() - copied = client.copy() - assert copied is not client + copied = test_client.copy() + assert copied is not test_client del copied - assert not client.is_closed() + assert not test_client.is_closed() def test_client_context_manager(self) -> None: - client = OnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=True) - with client as c2: - assert c2 is client + test_client = OnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=True) + with test_client as c2: + assert c2 is test_client assert not c2.is_closed() - assert not client.is_closed() - assert client.is_closed() + assert not test_client.is_closed() + assert test_client.is_closed() @pytest.mark.respx(base_url=base_url) - def test_client_response_validation_error(self, respx_mock: MockRouter) -> None: + def test_client_response_validation_error(self, respx_mock: MockRouter, client: OnebusawaySDK) -> None: class Model(BaseModel): foo: str respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) with pytest.raises(APIResponseValidationError) as exc: - self.client.get("/foo", cast_to=Model) + client.get("/foo", cast_to=Model) assert isinstance(exc.value.__cause__, ValidationError) @@ -680,11 +699,14 @@ class Model(BaseModel): with pytest.raises(APIResponseValidationError): strict_client.get("/foo", cast_to=Model) - client = OnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=False) + non_strict_client = OnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=False) - response = client.get("/foo", cast_to=Model) + response = non_strict_client.get("/foo", cast_to=Model) assert isinstance(response, str) # type: ignore[unreachable] + strict_client.close() + non_strict_client.close() + @pytest.mark.parametrize( "remaining_retries,retry_after,timeout", [ @@ -707,9 +729,9 @@ class Model(BaseModel): ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) - def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str, timeout: float) -> None: - client = OnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=True) - + def test_parse_retry_after_header( + self, remaining_retries: int, retry_after: str, timeout: float, client: OnebusawaySDK + ) -> None: headers = httpx.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) calculated = client._calculate_retry_timeout(remaining_retries, options, headers) @@ -723,7 +745,7 @@ def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, clien with pytest.raises(APITimeoutError): client.current_time.with_streaming_response.retrieve().__enter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(client) == 0 @mock.patch("onebusaway._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) @@ -732,7 +754,7 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client with pytest.raises(APIStatusError): client.current_time.with_streaming_response.retrieve().__enter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("onebusaway._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @@ -834,83 +856,77 @@ def test_default_client_creation(self) -> None: ) @pytest.mark.respx(base_url=base_url) - def test_follow_redirects(self, respx_mock: MockRouter) -> None: + def test_follow_redirects(self, respx_mock: MockRouter, client: OnebusawaySDK) -> None: # Test that the default follow_redirects=True allows following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) - response = self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + response = client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) assert response.status_code == 200 assert response.json() == {"status": "ok"} @pytest.mark.respx(base_url=base_url) - def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + def test_follow_redirects_disabled(self, respx_mock: MockRouter, client: OnebusawaySDK) -> None: # Test that follow_redirects=False prevents following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) with pytest.raises(APIStatusError) as exc_info: - self.client.post( - "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response - ) + client.post("/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response) assert exc_info.value.response.status_code == 302 assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" class TestAsyncOnebusawaySDK: - client = AsyncOnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=True) - @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_raw_response(self, respx_mock: MockRouter) -> None: + async def test_raw_response(self, respx_mock: MockRouter, async_client: AsyncOnebusawaySDK) -> None: respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.post("/foo", cast_to=httpx.Response) + response = await async_client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_raw_response_for_binary(self, respx_mock: MockRouter) -> None: + async def test_raw_response_for_binary(self, respx_mock: MockRouter, async_client: AsyncOnebusawaySDK) -> None: respx_mock.post("/foo").mock( return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') ) - response = await self.client.post("/foo", cast_to=httpx.Response) + response = await async_client.post("/foo", cast_to=httpx.Response) assert response.status_code == 200 assert isinstance(response, httpx.Response) assert response.json() == {"foo": "bar"} - def test_copy(self) -> None: - copied = self.client.copy() - assert id(copied) != id(self.client) + def test_copy(self, async_client: AsyncOnebusawaySDK) -> None: + copied = async_client.copy() + assert id(copied) != id(async_client) - copied = self.client.copy(api_key="another My API Key") + copied = async_client.copy(api_key="another My API Key") assert copied.api_key == "another My API Key" - assert self.client.api_key == "My API Key" + assert async_client.api_key == "My API Key" - def test_copy_default_options(self) -> None: + def test_copy_default_options(self, async_client: AsyncOnebusawaySDK) -> None: # options that have a default are overridden correctly - copied = self.client.copy(max_retries=7) + copied = async_client.copy(max_retries=7) assert copied.max_retries == 7 - assert self.client.max_retries == 2 + assert async_client.max_retries == 2 copied2 = copied.copy(max_retries=6) assert copied2.max_retries == 6 assert copied.max_retries == 7 # timeout - assert isinstance(self.client.timeout, httpx.Timeout) - copied = self.client.copy(timeout=None) + assert isinstance(async_client.timeout, httpx.Timeout) + copied = async_client.copy(timeout=None) assert copied.timeout is None - assert isinstance(self.client.timeout, httpx.Timeout) + assert isinstance(async_client.timeout, httpx.Timeout) - def test_copy_default_headers(self) -> None: + async def test_copy_default_headers(self) -> None: client = AsyncOnebusawaySDK( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} ) @@ -943,8 +959,9 @@ def test_copy_default_headers(self) -> None: match="`default_headers` and `set_default_headers` arguments are mutually exclusive", ): client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) + await client.close() - def test_copy_default_query(self) -> None: + async def test_copy_default_query(self) -> None: client = AsyncOnebusawaySDK( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"foo": "bar"} ) @@ -980,13 +997,15 @@ def test_copy_default_query(self) -> None: ): client.copy(set_default_query={}, default_query={"foo": "Bar"}) - def test_copy_signature(self) -> None: + await client.close() + + def test_copy_signature(self, async_client: AsyncOnebusawaySDK) -> None: # ensure the same parameters that can be passed to the client are defined in the `.copy()` method init_signature = inspect.signature( # mypy doesn't like that we access the `__init__` property. - self.client.__init__, # type: ignore[misc] + async_client.__init__, # type: ignore[misc] ) - copy_signature = inspect.signature(self.client.copy) + copy_signature = inspect.signature(async_client.copy) exclude_params = {"transport", "proxies", "_strict_response_validation"} for name in init_signature.parameters.keys(): @@ -997,12 +1016,12 @@ def test_copy_signature(self) -> None: assert copy_param is not None, f"copy() signature is missing the {name} param" @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") - def test_copy_build_request(self) -> None: + def test_copy_build_request(self, async_client: AsyncOnebusawaySDK) -> None: options = FinalRequestOptions(method="get", url="/foo") def build_request(options: FinalRequestOptions) -> None: - client = self.client.copy() - client._build_request(options) + client_copy = async_client.copy() + client_copy._build_request(options) # ensure that the machinery is warmed up before tracing starts. build_request(options) @@ -1058,12 +1077,12 @@ def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.Statistic print(frame) raise AssertionError() - async def test_request_timeout(self) -> None: - request = self.client._build_request(FinalRequestOptions(method="get", url="/foo")) + async def test_request_timeout(self, async_client: AsyncOnebusawaySDK) -> None: + request = async_client._build_request(FinalRequestOptions(method="get", url="/foo")) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT - request = self.client._build_request( + request = async_client._build_request( FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) ) timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore @@ -1078,6 +1097,8 @@ async def test_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(0) + await client.close() + async def test_http_client_timeout_option(self) -> None: # custom timeout given to the httpx client should be used async with httpx.AsyncClient(timeout=None) as http_client: @@ -1089,6 +1110,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == httpx.Timeout(None) + await client.close() + # no timeout given to the httpx client should not use the httpx default async with httpx.AsyncClient() as http_client: client = AsyncOnebusawaySDK( @@ -1099,6 +1122,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT + await client.close() + # explicitly passing the default timeout currently results in it being ignored async with httpx.AsyncClient(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: client = AsyncOnebusawaySDK( @@ -1109,6 +1134,8 @@ async def test_http_client_timeout_option(self) -> None: timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore assert timeout == DEFAULT_TIMEOUT # our default + await client.close() + def test_invalid_http_client(self) -> None: with pytest.raises(TypeError, match="Invalid `http_client` arg"): with httpx.Client() as http_client: @@ -1119,15 +1146,15 @@ def test_invalid_http_client(self) -> None: http_client=cast(Any, http_client), ) - def test_default_headers_option(self) -> None: - client = AsyncOnebusawaySDK( + async def test_default_headers_option(self) -> None: + test_client = AsyncOnebusawaySDK( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_headers={"X-Foo": "bar"} ) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "bar" assert request.headers.get("x-stainless-lang") == "python" - client2 = AsyncOnebusawaySDK( + test_client2 = AsyncOnebusawaySDK( base_url=base_url, api_key=api_key, _strict_response_validation=True, @@ -1136,11 +1163,14 @@ def test_default_headers_option(self) -> None: "X-Stainless-Lang": "my-overriding-header", }, ) - request = client2._build_request(FinalRequestOptions(method="get", url="/foo")) + request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) assert request.headers.get("x-foo") == "stainless" assert request.headers.get("x-stainless-lang") == "my-overriding-header" - def test_default_query_option(self) -> None: + await test_client.close() + await test_client2.close() + + async def test_default_query_option(self) -> None: client = AsyncOnebusawaySDK( base_url=base_url, api_key=api_key, _strict_response_validation=True, default_query={"query_param": "bar"} ) @@ -1159,8 +1189,8 @@ def test_default_query_option(self) -> None: url = httpx.URL(request.url) assert dict(url.params) == {"foo": "baz", "query_param": "overridden", "key": api_key} - def test_request_extra_json(self) -> None: - request = self.client._build_request( + def test_request_extra_json(self, client: OnebusawaySDK) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1171,7 +1201,7 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": False} - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1182,7 +1212,7 @@ def test_request_extra_json(self) -> None: assert data == {"baz": False} # `extra_json` takes priority over `json_data` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1193,8 +1223,8 @@ def test_request_extra_json(self) -> None: data = json.loads(request.content.decode("utf-8")) assert data == {"foo": "bar", "baz": None} - def test_request_extra_headers(self) -> None: - request = self.client._build_request( + def test_request_extra_headers(self, client: OnebusawaySDK) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1204,7 +1234,7 @@ def test_request_extra_headers(self) -> None: assert request.headers.get("X-Foo") == "Foo" # `extra_headers` takes priority over `default_headers` when keys clash - request = self.client.with_options(default_headers={"X-Bar": "true"})._build_request( + request = client.with_options(default_headers={"X-Bar": "true"})._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1215,8 +1245,8 @@ def test_request_extra_headers(self) -> None: ) assert request.headers.get("X-Bar") == "false" - def test_request_extra_query(self) -> None: - request = self.client._build_request( + def test_request_extra_query(self, client: OnebusawaySDK) -> None: + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1229,7 +1259,7 @@ def test_request_extra_query(self) -> None: assert params == {"my_query_param": "Foo", "key": api_key} # if both `query` and `extra_query` are given, they are merged - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1242,7 +1272,7 @@ def test_request_extra_query(self) -> None: params = dict(request.url.params) assert params == {"bar": "1", "foo": "2", "key": api_key} # `extra_query` takes priority over `query` when keys clash - request = self.client._build_request( + request = client._build_request( FinalRequestOptions( method="post", url="/foo", @@ -1285,7 +1315,7 @@ def test_multipart_repeating_array(self, async_client: AsyncOnebusawaySDK) -> No ] @pytest.mark.respx(base_url=base_url) - async def test_basic_union_response(self, respx_mock: MockRouter) -> None: + async def test_basic_union_response(self, respx_mock: MockRouter, async_client: AsyncOnebusawaySDK) -> None: class Model1(BaseModel): name: str @@ -1294,12 +1324,14 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" @pytest.mark.respx(base_url=base_url) - async def test_union_response_different_types(self, respx_mock: MockRouter) -> None: + async def test_union_response_different_types( + self, respx_mock: MockRouter, async_client: AsyncOnebusawaySDK + ) -> None: """Union of objects with the same field name using a different type""" class Model1(BaseModel): @@ -1310,18 +1342,20 @@ class Model2(BaseModel): respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model2) assert response.foo == "bar" respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) - response = await self.client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) + response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) assert isinstance(response, Model1) assert response.foo == 1 @pytest.mark.respx(base_url=base_url) - async def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter) -> None: + async def test_non_application_json_content_type_for_json_data( + self, respx_mock: MockRouter, async_client: AsyncOnebusawaySDK + ) -> None: """ Response that sets Content-Type to something other than application/json but returns json data """ @@ -1337,11 +1371,11 @@ class Model(BaseModel): ) ) - response = await self.client.get("/foo", cast_to=Model) + response = await async_client.get("/foo", cast_to=Model) assert isinstance(response, Model) assert response.foo == 2 - def test_base_url_setter(self) -> None: + async def test_base_url_setter(self) -> None: client = AsyncOnebusawaySDK( base_url="https://example.com/from_init", api_key=api_key, _strict_response_validation=True ) @@ -1351,7 +1385,9 @@ def test_base_url_setter(self) -> None: assert client.base_url == "https://example.com/from_setter/" - def test_base_url_env(self) -> None: + await client.close() + + async def test_base_url_env(self) -> None: with update_env(ONEBUSAWAY_SDK_BASE_URL="http://localhost:5000/from/env"): client = AsyncOnebusawaySDK(api_key=api_key, _strict_response_validation=True) assert client.base_url == "http://localhost:5000/from/env/" @@ -1371,7 +1407,7 @@ def test_base_url_env(self) -> None: ], ids=["standard", "custom http client"], ) - def test_base_url_trailing_slash(self, client: AsyncOnebusawaySDK) -> None: + async def test_base_url_trailing_slash(self, client: AsyncOnebusawaySDK) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1381,6 +1417,7 @@ def test_base_url_trailing_slash(self, client: AsyncOnebusawaySDK) -> None: ) excepted_url = f"http://localhost:5000/custom/path/foo?key={urllib.parse.quote_plus(client.api_key)}" assert request.url == excepted_url + await client.close() @pytest.mark.parametrize( "client", @@ -1397,7 +1434,7 @@ def test_base_url_trailing_slash(self, client: AsyncOnebusawaySDK) -> None: ], ids=["standard", "custom http client"], ) - def test_base_url_no_trailing_slash(self, client: AsyncOnebusawaySDK) -> None: + async def test_base_url_no_trailing_slash(self, client: AsyncOnebusawaySDK) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1408,6 +1445,7 @@ def test_base_url_no_trailing_slash(self, client: AsyncOnebusawaySDK) -> None: expected_url = f"http://localhost:5000/custom/path/foo?key={urllib.parse.quote_plus(client.api_key)}" assert request.url == expected_url + await client.close() @pytest.mark.parametrize( "client", @@ -1424,7 +1462,7 @@ def test_base_url_no_trailing_slash(self, client: AsyncOnebusawaySDK) -> None: ], ids=["standard", "custom http client"], ) - def test_absolute_request_url(self, client: AsyncOnebusawaySDK) -> None: + async def test_absolute_request_url(self, client: AsyncOnebusawaySDK) -> None: request = client._build_request( FinalRequestOptions( method="post", @@ -1434,37 +1472,39 @@ def test_absolute_request_url(self, client: AsyncOnebusawaySDK) -> None: ) expected_url = f"https://myapi.com/foo?key={urllib.parse.quote_plus(client.api_key)}" assert request.url == expected_url + await client.close() async def test_copied_client_does_not_close_http(self) -> None: - client = AsyncOnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=True) - assert not client.is_closed() + test_client = AsyncOnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=True) + assert not test_client.is_closed() - copied = client.copy() - assert copied is not client + copied = test_client.copy() + assert copied is not test_client del copied await asyncio.sleep(0.2) - assert not client.is_closed() + assert not test_client.is_closed() async def test_client_context_manager(self) -> None: - client = AsyncOnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=True) - async with client as c2: - assert c2 is client + test_client = AsyncOnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=True) + async with test_client as c2: + assert c2 is test_client assert not c2.is_closed() - assert not client.is_closed() - assert client.is_closed() + assert not test_client.is_closed() + assert test_client.is_closed() @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio - async def test_client_response_validation_error(self, respx_mock: MockRouter) -> None: + async def test_client_response_validation_error( + self, respx_mock: MockRouter, async_client: AsyncOnebusawaySDK + ) -> None: class Model(BaseModel): foo: str respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) with pytest.raises(APIResponseValidationError) as exc: - await self.client.get("/foo", cast_to=Model) + await async_client.get("/foo", cast_to=Model) assert isinstance(exc.value.__cause__, ValidationError) @@ -1475,7 +1515,6 @@ async def test_client_max_retries_validation(self) -> None: ) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: class Model(BaseModel): name: str @@ -1487,11 +1526,14 @@ class Model(BaseModel): with pytest.raises(APIResponseValidationError): await strict_client.get("/foo", cast_to=Model) - client = AsyncOnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=False) + non_strict_client = AsyncOnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=False) - response = await client.get("/foo", cast_to=Model) + response = await non_strict_client.get("/foo", cast_to=Model) assert isinstance(response, str) # type: ignore[unreachable] + await strict_client.close() + await non_strict_client.close() + @pytest.mark.parametrize( "remaining_retries,retry_after,timeout", [ @@ -1514,13 +1556,12 @@ class Model(BaseModel): ], ) @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) - @pytest.mark.asyncio - async def test_parse_retry_after_header(self, remaining_retries: int, retry_after: str, timeout: float) -> None: - client = AsyncOnebusawaySDK(base_url=base_url, api_key=api_key, _strict_response_validation=True) - + async def test_parse_retry_after_header( + self, remaining_retries: int, retry_after: str, timeout: float, async_client: AsyncOnebusawaySDK + ) -> None: headers = httpx.Headers({"retry-after": retry_after}) options = FinalRequestOptions(method="get", url="/foo", max_retries=3) - calculated = client._calculate_retry_timeout(remaining_retries, options, headers) + calculated = async_client._calculate_retry_timeout(remaining_retries, options, headers) assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] @mock.patch("onebusaway._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @@ -1533,7 +1574,7 @@ async def test_retrying_timeout_errors_doesnt_leak( with pytest.raises(APITimeoutError): await async_client.current_time.with_streaming_response.retrieve().__aenter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(async_client) == 0 @mock.patch("onebusaway._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) @@ -1544,12 +1585,11 @@ async def test_retrying_status_errors_doesnt_leak( with pytest.raises(APIStatusError): await async_client.current_time.with_streaming_response.retrieve().__aenter__() - assert _get_open_connections(self.client) == 0 + assert _get_open_connections(async_client) == 0 @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("onebusaway._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio @pytest.mark.parametrize("failure_mode", ["status", "exception"]) async def test_retries_taken( self, @@ -1581,7 +1621,6 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("onebusaway._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_omit_retry_count_header( self, async_client: AsyncOnebusawaySDK, failures_before_success: int, respx_mock: MockRouter ) -> None: @@ -1607,7 +1646,6 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) @mock.patch("onebusaway._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) - @pytest.mark.asyncio async def test_overwrite_retry_count_header( self, async_client: AsyncOnebusawaySDK, failures_before_success: int, respx_mock: MockRouter ) -> None: @@ -1655,26 +1693,26 @@ async def test_default_client_creation(self) -> None: ) @pytest.mark.respx(base_url=base_url) - async def test_follow_redirects(self, respx_mock: MockRouter) -> None: + async def test_follow_redirects(self, respx_mock: MockRouter, async_client: AsyncOnebusawaySDK) -> None: # Test that the default follow_redirects=True allows following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) - response = await self.client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) + response = await async_client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) assert response.status_code == 200 assert response.json() == {"status": "ok"} @pytest.mark.respx(base_url=base_url) - async def test_follow_redirects_disabled(self, respx_mock: MockRouter) -> None: + async def test_follow_redirects_disabled(self, respx_mock: MockRouter, async_client: AsyncOnebusawaySDK) -> None: # Test that follow_redirects=False prevents following redirects respx_mock.post("/redirect").mock( return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) ) with pytest.raises(APIStatusError) as exc_info: - await self.client.post( + await async_client.post( "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response ) From aa8df91bb2ba826f49bacf3a2a777579931487d9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 06:10:04 +0000 Subject: [PATCH 02/18] chore(internal): grammar fix (it's -> its) --- src/onebusaway/_utils/_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/onebusaway/_utils/_utils.py b/src/onebusaway/_utils/_utils.py index 50d5926..eec7f4a 100644 --- a/src/onebusaway/_utils/_utils.py +++ b/src/onebusaway/_utils/_utils.py @@ -133,7 +133,7 @@ def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]: # Type safe methods for narrowing types with TypeVars. # The default narrowing for isinstance(obj, dict) is dict[unknown, unknown], # however this cause Pyright to rightfully report errors. As we know we don't -# care about the contained types we can safely use `object` in it's place. +# care about the contained types we can safely use `object` in its place. # # There are two separate functions defined, `is_*` and `is_*_t` for different use cases. # `is_*` is for when you're dealing with an unknown input From b633259385cddf32422b425a174a2a7dbe34021c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 2 Jan 2026 16:09:51 +0000 Subject: [PATCH 03/18] chore(package): drop Python 3.8 support --- README.md | 4 ++-- pyproject.toml | 5 ++--- src/onebusaway/_utils/_sync.py | 34 +++------------------------------- 3 files changed, 7 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 66f764f..dc90695 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![PyPI version](https://img.shields.io/pypi/v/onebusaway.svg?label=pypi%20(stable))](https://pypi.org/project/onebusaway/) -The Onebusaway SDK Python library provides convenient access to the Onebusaway SDK REST API from any Python 3.8+ +The Onebusaway SDK Python library provides convenient access to the Onebusaway SDK REST API from any Python 3.9+ application. The library includes type definitions for all request params and response fields, and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx). @@ -355,7 +355,7 @@ print(onebusaway.__version__) ## Requirements -Python 3.8 or higher. +Python 3.9 or higher. ## Contributing diff --git a/pyproject.toml b/pyproject.toml index 5c9db68..c6d69b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,11 +15,10 @@ dependencies = [ "distro>=1.7.0, <2", "sniffio", ] -requires-python = ">= 3.8" +requires-python = ">= 3.9" classifiers = [ "Typing :: Typed", "Intended Audience :: Developers", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -141,7 +140,7 @@ filterwarnings = [ # there are a couple of flags that are still disabled by # default in strict mode as they are experimental and niche. typeCheckingMode = "strict" -pythonVersion = "3.8" +pythonVersion = "3.9" exclude = [ "_dev", diff --git a/src/onebusaway/_utils/_sync.py b/src/onebusaway/_utils/_sync.py index ad7ec71..f6027c1 100644 --- a/src/onebusaway/_utils/_sync.py +++ b/src/onebusaway/_utils/_sync.py @@ -1,10 +1,8 @@ from __future__ import annotations -import sys import asyncio import functools -import contextvars -from typing import Any, TypeVar, Callable, Awaitable +from typing import TypeVar, Callable, Awaitable from typing_extensions import ParamSpec import anyio @@ -15,34 +13,11 @@ T_ParamSpec = ParamSpec("T_ParamSpec") -if sys.version_info >= (3, 9): - _asyncio_to_thread = asyncio.to_thread -else: - # backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread - # for Python 3.8 support - async def _asyncio_to_thread( - func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs - ) -> Any: - """Asynchronously run function *func* in a separate thread. - - Any *args and **kwargs supplied for this function are directly passed - to *func*. Also, the current :class:`contextvars.Context` is propagated, - allowing context variables from the main thread to be accessed in the - separate thread. - - Returns a coroutine that can be awaited to get the eventual result of *func*. - """ - loop = asyncio.events.get_running_loop() - ctx = contextvars.copy_context() - func_call = functools.partial(ctx.run, func, *args, **kwargs) - return await loop.run_in_executor(None, func_call) - - async def to_thread( func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs ) -> T_Retval: if sniffio.current_async_library() == "asyncio": - return await _asyncio_to_thread(func, *args, **kwargs) + return await asyncio.to_thread(func, *args, **kwargs) return await anyio.to_thread.run_sync( functools.partial(func, *args, **kwargs), @@ -53,10 +28,7 @@ async def to_thread( def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: """ Take a blocking function and create an async one that receives the same - positional and keyword arguments. For python version 3.9 and above, it uses - asyncio.to_thread to run the function in a separate thread. For python version - 3.8, it uses locally defined copy of the asyncio.to_thread function which was - introduced in python 3.9. + positional and keyword arguments. Usage: From 2ebc5184554db31387b2f683265720d58dd9bb2f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 06:04:11 +0000 Subject: [PATCH 04/18] fix: compat with Python 3.14 --- src/onebusaway/_models.py | 11 ++++++++--- tests/test_models.py | 8 ++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/onebusaway/_models.py b/src/onebusaway/_models.py index 6a3cd1d..fcec2cf 100644 --- a/src/onebusaway/_models.py +++ b/src/onebusaway/_models.py @@ -2,6 +2,7 @@ import os import inspect +import weakref from typing import TYPE_CHECKING, Any, Type, Union, Generic, TypeVar, Callable, Optional, cast from datetime import date, datetime from typing_extensions import ( @@ -573,6 +574,9 @@ class CachedDiscriminatorType(Protocol): __discriminator__: DiscriminatorDetails +DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary() + + class DiscriminatorDetails: field_name: str """The name of the discriminator field in the variant class, e.g. @@ -615,8 +619,9 @@ def __init__( def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None: - if isinstance(union, CachedDiscriminatorType): - return union.__discriminator__ + cached = DISCRIMINATOR_CACHE.get(union) + if cached is not None: + return cached discriminator_field_name: str | None = None @@ -669,7 +674,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, discriminator_field=discriminator_field_name, discriminator_alias=discriminator_alias, ) - cast(CachedDiscriminatorType, union).__discriminator__ = details + DISCRIMINATOR_CACHE.setdefault(union, details) return details diff --git a/tests/test_models.py b/tests/test_models.py index 7f54642..f73d5e1 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -9,7 +9,7 @@ from onebusaway._utils import PropertyInfo from onebusaway._compat import PYDANTIC_V1, parse_obj, model_dump, model_json -from onebusaway._models import BaseModel, construct_type +from onebusaway._models import DISCRIMINATOR_CACHE, BaseModel, construct_type class BasicModel(BaseModel): @@ -809,7 +809,7 @@ class B(BaseModel): UnionType = cast(Any, Union[A, B]) - assert not hasattr(UnionType, "__discriminator__") + assert not DISCRIMINATOR_CACHE.get(UnionType) m = construct_type( value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")]) @@ -818,7 +818,7 @@ class B(BaseModel): assert m.type == "b" assert m.data == "foo" # type: ignore[comparison-overlap] - discriminator = UnionType.__discriminator__ + discriminator = DISCRIMINATOR_CACHE.get(UnionType) assert discriminator is not None m = construct_type( @@ -830,7 +830,7 @@ class B(BaseModel): # if the discriminator details object stays the same between invocations then # we hit the cache - assert UnionType.__discriminator__ is discriminator + assert DISCRIMINATOR_CACHE.get(UnionType) is discriminator @pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") From 37abc5b808843321a5011b935590c5d3455f0c27 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 12 Nov 2025 05:40:09 +0000 Subject: [PATCH 05/18] fix(compat): update signatures of `model_dump` and `model_dump_json` for Pydantic v1 --- src/onebusaway/_models.py | 41 +++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/onebusaway/_models.py b/src/onebusaway/_models.py index fcec2cf..ca9500b 100644 --- a/src/onebusaway/_models.py +++ b/src/onebusaway/_models.py @@ -257,15 +257,16 @@ def model_dump( mode: Literal["json", "python"] | str = "python", include: IncEx | None = None, exclude: IncEx | None = None, + context: Any | None = None, by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, + exclude_computed_fields: bool = False, round_trip: bool = False, warnings: bool | Literal["none", "warn", "error"] = True, - context: dict[str, Any] | None = None, - serialize_as_any: bool = False, fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, ) -> dict[str, Any]: """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump @@ -273,16 +274,24 @@ def model_dump( Args: mode: The mode in which `to_python` should run. - If mode is 'json', the dictionary will only contain JSON serializable types. - If mode is 'python', the dictionary may contain any Python objects. - include: A list of fields to include in the output. - exclude: A list of fields to exclude from the output. + If mode is 'json', the output will only contain JSON serializable types. + If mode is 'python', the output may contain non-JSON-serializable Python objects. + include: A set of fields to include in the output. + exclude: A set of fields to exclude from the output. + context: Additional context to pass to the serializer. by_alias: Whether to use the field's alias in the dictionary key if defined. - exclude_unset: Whether to exclude fields that are unset or None from the output. - exclude_defaults: Whether to exclude fields that are set to their default value from the output. - exclude_none: Whether to exclude fields that have a value of `None` from the output. - round_trip: Whether to enable serialization and deserialization round-trip support. - warnings: Whether to log warnings when invalid fields are encountered. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value. + exclude_none: Whether to exclude fields that have a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. Returns: A dictionary representation of the model. @@ -299,6 +308,8 @@ def model_dump( raise ValueError("serialize_as_any is only supported in Pydantic v2") if fallback is not None: raise ValueError("fallback is only supported in Pydantic v2") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") dumped = super().dict( # pyright: ignore[reportDeprecated] include=include, exclude=exclude, @@ -315,15 +326,17 @@ def model_dump_json( self, *, indent: int | None = None, + ensure_ascii: bool = False, include: IncEx | None = None, exclude: IncEx | None = None, + context: Any | None = None, by_alias: bool | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, + exclude_computed_fields: bool = False, round_trip: bool = False, warnings: bool | Literal["none", "warn", "error"] = True, - context: dict[str, Any] | None = None, fallback: Callable[[Any], Any] | None = None, serialize_as_any: bool = False, ) -> str: @@ -355,6 +368,10 @@ def model_dump_json( raise ValueError("serialize_as_any is only supported in Pydantic v2") if fallback is not None: raise ValueError("fallback is only supported in Pydantic v2") + if ensure_ascii != False: + raise ValueError("ensure_ascii is only supported in Pydantic v2") + if exclude_computed_fields != False: + raise ValueError("exclude_computed_fields is only supported in Pydantic v2") return super().json( # type: ignore[reportDeprecated] indent=indent, include=include, From 5ba9679c37d905d2b994fb3ad033825142ee19e2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 22 Nov 2025 05:10:10 +0000 Subject: [PATCH 06/18] chore: add Python 3.14 classifier and testing --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index c6d69b4..f6f299d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Operating System :: OS Independent", "Operating System :: POSIX", "Operating System :: MacOS", From 75f1288ddc3202c2fe6850b8f968720ed88cb470 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 28 Nov 2025 03:47:49 +0000 Subject: [PATCH 07/18] fix: ensure streams are always closed --- src/onebusaway/_streaming.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/onebusaway/_streaming.py b/src/onebusaway/_streaming.py index 19eceeb..288db03 100644 --- a/src/onebusaway/_streaming.py +++ b/src/onebusaway/_streaming.py @@ -54,11 +54,12 @@ def __stream__(self) -> Iterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - - # As we might not fully consume the response stream, we need to close it explicitly - response.close() + try: + for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + response.close() def __enter__(self) -> Self: return self @@ -117,11 +118,12 @@ async def __stream__(self) -> AsyncIterator[_T]: process_data = self._client._process_response_data iterator = self._iter_events() - async for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - - # As we might not fully consume the response stream, we need to close it explicitly - await response.aclose() + try: + async for sse in iterator: + yield process_data(data=sse.json(), cast_to=cast_to, response=response) + finally: + # Ensure the response is closed even if the consumer doesn't read all data + await response.aclose() async def __aenter__(self) -> Self: return self From 167648d8fb485e522aa49611ee25523190b78c9a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 28 Nov 2025 03:49:18 +0000 Subject: [PATCH 08/18] chore(deps): mypy 1.18.1 has a regression, pin to 1.17 --- pyproject.toml | 2 +- requirements-dev.lock | 4 +++- requirements.lock | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f6f299d..b83c0ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,7 @@ managed = true # version pins are in requirements-dev.lock dev-dependencies = [ "pyright==1.1.399", - "mypy", + "mypy==1.17", "respx", "pytest", "pytest-asyncio", diff --git a/requirements-dev.lock b/requirements-dev.lock index 41b54ec..27d3dd3 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -72,7 +72,7 @@ mdurl==0.1.2 multidict==6.4.4 # via aiohttp # via yarl -mypy==1.14.1 +mypy==1.17.0 mypy-extensions==1.0.0 # via mypy nodeenv==1.8.0 @@ -81,6 +81,8 @@ nox==2023.4.22 packaging==23.2 # via nox # via pytest +pathspec==0.12.1 + # via mypy platformdirs==3.11.0 # via virtualenv pluggy==1.5.0 diff --git a/requirements.lock b/requirements.lock index 11442de..d7c68e1 100644 --- a/requirements.lock +++ b/requirements.lock @@ -55,21 +55,21 @@ multidict==6.4.4 propcache==0.3.1 # via aiohttp # via yarl -pydantic==2.11.9 +pydantic==2.12.5 # via onebusaway -pydantic-core==2.33.2 +pydantic-core==2.41.5 # via pydantic sniffio==1.3.0 # via anyio # via onebusaway -typing-extensions==4.12.2 +typing-extensions==4.15.0 # via anyio # via multidict # via onebusaway # via pydantic # via pydantic-core # via typing-inspection -typing-inspection==0.4.1 +typing-inspection==0.4.2 # via pydantic yarl==1.20.0 # via aiohttp From 4fd805dfa1c4efe2fd53d7aa46c75e368c97463f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 07:45:52 +0000 Subject: [PATCH 09/18] chore: update lockfile --- pyproject.toml | 14 +++--- requirements-dev.lock | 108 +++++++++++++++++++++++------------------- requirements.lock | 31 ++++++------ 3 files changed, 83 insertions(+), 70 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index b83c0ec..9f61ec1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,14 +7,16 @@ license = "Apache-2.0" authors = [ { name = "Onebusaway SDK", email = "info@onebusaway.org" }, ] + dependencies = [ - "httpx>=0.23.0, <1", - "pydantic>=1.9.0, <3", - "typing-extensions>=4.10, <5", - "anyio>=3.5.0, <5", - "distro>=1.7.0, <2", - "sniffio", + "httpx>=0.23.0, <1", + "pydantic>=1.9.0, <3", + "typing-extensions>=4.10, <5", + "anyio>=3.5.0, <5", + "distro>=1.7.0, <2", + "sniffio", ] + requires-python = ">= 3.9" classifiers = [ "Typing :: Typed", diff --git a/requirements-dev.lock b/requirements-dev.lock index 27d3dd3..69573c8 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -12,40 +12,45 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.12.8 +aiohttp==3.13.2 # via httpx-aiohttp # via onebusaway -aiosignal==1.3.2 +aiosignal==1.4.0 # via aiohttp -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -anyio==4.4.0 +anyio==4.12.0 # via httpx # via onebusaway -argcomplete==3.1.2 +argcomplete==3.6.3 # via nox async-timeout==5.0.1 # via aiohttp -attrs==25.3.0 +attrs==25.4.0 # via aiohttp -certifi==2023.7.22 + # via nox +backports-asyncio-runner==1.2.0 + # via pytest-asyncio +certifi==2025.11.12 # via httpcore # via httpx -colorlog==6.7.0 +colorlog==6.10.1 + # via nox +dependency-groups==1.3.1 # via nox -dirty-equals==0.6.0 -distlib==0.3.7 +dirty-equals==0.11 +distlib==0.4.0 # via virtualenv -distro==1.8.0 +distro==1.9.0 # via onebusaway -exceptiongroup==1.2.2 +exceptiongroup==1.3.1 # via anyio # via pytest -execnet==2.1.1 +execnet==2.1.2 # via pytest-xdist -filelock==3.12.4 +filelock==3.19.1 # via virtualenv -frozenlist==1.6.2 +frozenlist==1.8.0 # via aiohttp # via aiosignal h11==0.16.0 @@ -58,82 +63,87 @@ httpx==0.28.1 # via respx httpx-aiohttp==0.1.9 # via onebusaway -idna==3.4 +humanize==4.13.0 + # via nox +idna==3.11 # via anyio # via httpx # via yarl -importlib-metadata==7.0.0 -iniconfig==2.0.0 +importlib-metadata==8.7.0 +iniconfig==2.1.0 # via pytest markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py -multidict==6.4.4 +multidict==6.7.0 # via aiohttp # via yarl mypy==1.17.0 -mypy-extensions==1.0.0 +mypy-extensions==1.1.0 # via mypy -nodeenv==1.8.0 +nodeenv==1.9.1 # via pyright -nox==2023.4.22 -packaging==23.2 +nox==2025.11.12 +packaging==25.0 + # via dependency-groups # via nox # via pytest pathspec==0.12.1 # via mypy -platformdirs==3.11.0 +platformdirs==4.4.0 # via virtualenv -pluggy==1.5.0 +pluggy==1.6.0 # via pytest -propcache==0.3.1 +propcache==0.4.1 # via aiohttp # via yarl -pydantic==2.11.9 +pydantic==2.12.5 # via onebusaway -pydantic-core==2.33.2 +pydantic-core==2.41.5 # via pydantic -pygments==2.18.0 +pygments==2.19.2 + # via pytest # via rich pyright==1.1.399 -pytest==8.3.3 +pytest==8.4.2 # via pytest-asyncio # via pytest-xdist -pytest-asyncio==0.24.0 -pytest-xdist==3.7.0 -python-dateutil==2.8.2 +pytest-asyncio==1.2.0 +pytest-xdist==3.8.0 +python-dateutil==2.9.0.post0 # via time-machine -pytz==2023.3.post1 - # via dirty-equals respx==0.22.0 -rich==13.7.1 -ruff==0.9.4 -setuptools==68.2.2 - # via nodeenv -six==1.16.0 +rich==14.2.0 +ruff==0.14.7 +six==1.17.0 # via python-dateutil -sniffio==1.3.0 - # via anyio +sniffio==1.3.1 # via onebusaway -time-machine==2.9.0 -tomli==2.0.2 +time-machine==2.19.0 +tomli==2.3.0 + # via dependency-groups # via mypy + # via nox # via pytest -typing-extensions==4.12.2 +typing-extensions==4.15.0 + # via aiosignal # via anyio + # via exceptiongroup # via multidict # via mypy # via onebusaway # via pydantic # via pydantic-core # via pyright + # via pytest-asyncio # via typing-inspection -typing-inspection==0.4.1 + # via virtualenv +typing-inspection==0.4.2 # via pydantic -virtualenv==20.24.5 +virtualenv==20.35.4 # via nox -yarl==1.20.0 +yarl==1.22.0 # via aiohttp -zipp==3.17.0 +zipp==3.23.0 # via importlib-metadata diff --git a/requirements.lock b/requirements.lock index d7c68e1..2c479e1 100644 --- a/requirements.lock +++ b/requirements.lock @@ -12,28 +12,28 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.12.8 +aiohttp==3.13.2 # via httpx-aiohttp # via onebusaway -aiosignal==1.3.2 +aiosignal==1.4.0 # via aiohttp -annotated-types==0.6.0 +annotated-types==0.7.0 # via pydantic -anyio==4.4.0 +anyio==4.12.0 # via httpx # via onebusaway async-timeout==5.0.1 # via aiohttp -attrs==25.3.0 +attrs==25.4.0 # via aiohttp -certifi==2023.7.22 +certifi==2025.11.12 # via httpcore # via httpx -distro==1.8.0 +distro==1.9.0 # via onebusaway -exceptiongroup==1.2.2 +exceptiongroup==1.3.1 # via anyio -frozenlist==1.6.2 +frozenlist==1.8.0 # via aiohttp # via aiosignal h11==0.16.0 @@ -45,25 +45,26 @@ httpx==0.28.1 # via onebusaway httpx-aiohttp==0.1.9 # via onebusaway -idna==3.4 +idna==3.11 # via anyio # via httpx # via yarl -multidict==6.4.4 +multidict==6.7.0 # via aiohttp # via yarl -propcache==0.3.1 +propcache==0.4.1 # via aiohttp # via yarl pydantic==2.12.5 # via onebusaway pydantic-core==2.41.5 # via pydantic -sniffio==1.3.0 - # via anyio +sniffio==1.3.1 # via onebusaway typing-extensions==4.15.0 + # via aiosignal # via anyio + # via exceptiongroup # via multidict # via onebusaway # via pydantic @@ -71,5 +72,5 @@ typing-extensions==4.15.0 # via typing-inspection typing-inspection==0.4.2 # via pydantic -yarl==1.20.0 +yarl==1.22.0 # via aiohttp From a2ac5df1da8f164cbe85325385266b5340fd361b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 07:56:00 +0000 Subject: [PATCH 10/18] chore(docs): use environment variables for authentication in code snippets --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dc90695..1d0febd 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ pip install onebusaway[aiohttp] Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: ```python +import os import asyncio from onebusaway import DefaultAioHttpClient from onebusaway import AsyncOnebusawaySDK @@ -86,7 +87,7 @@ from onebusaway import AsyncOnebusawaySDK async def main() -> None: async with AsyncOnebusawaySDK( - api_key="My API Key", + api_key=os.environ.get("ONEBUSAWAY_API_KEY"), # This is the default and can be omitted http_client=DefaultAioHttpClient(), ) as client: current_time = await client.current_time.retrieve() From f10f3734af08ea934c7b5be9de0cd2af106afaea Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 05:41:05 +0000 Subject: [PATCH 11/18] fix(types): allow pyright to infer TypedDict types within SequenceNotStr --- src/onebusaway/_types.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/onebusaway/_types.py b/src/onebusaway/_types.py index f005a2e..93ca645 100644 --- a/src/onebusaway/_types.py +++ b/src/onebusaway/_types.py @@ -243,6 +243,9 @@ class HttpxSendArgs(TypedDict, total=False): if TYPE_CHECKING: # This works because str.__contains__ does not accept object (either in typeshed or at runtime) # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 + # + # Note: index() and count() methods are intentionally omitted to allow pyright to properly + # infer TypedDict types when dict literals are used in lists assigned to SequenceNotStr. class SequenceNotStr(Protocol[_T_co]): @overload def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... @@ -251,8 +254,6 @@ def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... def __contains__(self, value: object, /) -> bool: ... def __len__(self) -> int: ... def __iter__(self) -> Iterator[_T_co]: ... - def index(self, value: Any, start: int = 0, stop: int = ..., /) -> int: ... - def count(self, value: Any, /) -> int: ... def __reversed__(self) -> Iterator[_T_co]: ... else: # just point this to a normal `Sequence` at runtime to avoid having to special case From 5daefdde179696d3ade876b33b94fb79f5972155 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 05:42:38 +0000 Subject: [PATCH 12/18] chore: add missing docstrings --- src/onebusaway/types/arrival_and_departure_list_response.py | 6 ++++++ .../types/arrival_and_departure_retrieve_response.py | 6 ++++++ src/onebusaway/types/trip_detail_retrieve_response.py | 4 ++++ src/onebusaway/types/trip_for_vehicle_retrieve_response.py | 4 ++++ src/onebusaway/types/trips_for_location_list_response.py | 4 ++++ src/onebusaway/types/trips_for_route_list_response.py | 4 ++++ src/onebusaway/types/vehicles_for_agency_list_response.py | 4 ++++ 7 files changed, 32 insertions(+) diff --git a/src/onebusaway/types/arrival_and_departure_list_response.py b/src/onebusaway/types/arrival_and_departure_list_response.py index cbabf18..cb8aeb3 100644 --- a/src/onebusaway/types/arrival_and_departure_list_response.py +++ b/src/onebusaway/types/arrival_and_departure_list_response.py @@ -20,6 +20,8 @@ class ArrivalAndDepartureListResponseDataEntryArrivalsAndDepartureTripStatusLastKnownLocation(BaseModel): + """Last known location of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the last known location of the transit vehicle.""" @@ -28,6 +30,8 @@ class ArrivalAndDepartureListResponseDataEntryArrivalsAndDepartureTripStatusLast class ArrivalAndDepartureListResponseDataEntryArrivalsAndDepartureTripStatusPosition(BaseModel): + """Current position of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the current position of the transit vehicle.""" @@ -36,6 +40,8 @@ class ArrivalAndDepartureListResponseDataEntryArrivalsAndDepartureTripStatusPosi class ArrivalAndDepartureListResponseDataEntryArrivalsAndDepartureTripStatus(BaseModel): + """Trip-specific status for the arriving transit vehicle.""" + active_trip_id: str = FieldInfo(alias="activeTripId") """Trip ID of the trip the vehicle is actively serving.""" diff --git a/src/onebusaway/types/arrival_and_departure_retrieve_response.py b/src/onebusaway/types/arrival_and_departure_retrieve_response.py index a0bc771..a4ed922 100644 --- a/src/onebusaway/types/arrival_and_departure_retrieve_response.py +++ b/src/onebusaway/types/arrival_and_departure_retrieve_response.py @@ -19,6 +19,8 @@ class ArrivalAndDepartureRetrieveResponseDataEntryTripStatusLastKnownLocation(BaseModel): + """Last known location of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the last known location of the transit vehicle.""" @@ -27,6 +29,8 @@ class ArrivalAndDepartureRetrieveResponseDataEntryTripStatusLastKnownLocation(Ba class ArrivalAndDepartureRetrieveResponseDataEntryTripStatusPosition(BaseModel): + """Current position of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the current position of the transit vehicle.""" @@ -35,6 +39,8 @@ class ArrivalAndDepartureRetrieveResponseDataEntryTripStatusPosition(BaseModel): class ArrivalAndDepartureRetrieveResponseDataEntryTripStatus(BaseModel): + """Trip-specific status for the arriving transit vehicle.""" + active_trip_id: str = FieldInfo(alias="activeTripId") """Trip ID of the trip the vehicle is actively serving.""" diff --git a/src/onebusaway/types/trip_detail_retrieve_response.py b/src/onebusaway/types/trip_detail_retrieve_response.py index 4b76689..cb1552c 100644 --- a/src/onebusaway/types/trip_detail_retrieve_response.py +++ b/src/onebusaway/types/trip_detail_retrieve_response.py @@ -47,6 +47,8 @@ class TripDetailRetrieveResponseDataEntrySchedule(BaseModel): class TripDetailRetrieveResponseDataEntryStatusLastKnownLocation(BaseModel): + """Last known location of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the last known location of the transit vehicle.""" @@ -55,6 +57,8 @@ class TripDetailRetrieveResponseDataEntryStatusLastKnownLocation(BaseModel): class TripDetailRetrieveResponseDataEntryStatusPosition(BaseModel): + """Current position of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the current position of the transit vehicle.""" diff --git a/src/onebusaway/types/trip_for_vehicle_retrieve_response.py b/src/onebusaway/types/trip_for_vehicle_retrieve_response.py index 136b96c..3ee8582 100644 --- a/src/onebusaway/types/trip_for_vehicle_retrieve_response.py +++ b/src/onebusaway/types/trip_for_vehicle_retrieve_response.py @@ -47,6 +47,8 @@ class TripForVehicleRetrieveResponseDataEntrySchedule(BaseModel): class TripForVehicleRetrieveResponseDataEntryStatusLastKnownLocation(BaseModel): + """Last known location of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the last known location of the transit vehicle.""" @@ -55,6 +57,8 @@ class TripForVehicleRetrieveResponseDataEntryStatusLastKnownLocation(BaseModel): class TripForVehicleRetrieveResponseDataEntryStatusPosition(BaseModel): + """Current position of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the current position of the transit vehicle.""" diff --git a/src/onebusaway/types/trips_for_location_list_response.py b/src/onebusaway/types/trips_for_location_list_response.py index 68ae881..b104313 100644 --- a/src/onebusaway/types/trips_for_location_list_response.py +++ b/src/onebusaway/types/trips_for_location_list_response.py @@ -47,6 +47,8 @@ class TripsForLocationListResponseDataListSchedule(BaseModel): class TripsForLocationListResponseDataListStatusLastKnownLocation(BaseModel): + """Last known location of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the last known location of the transit vehicle.""" @@ -55,6 +57,8 @@ class TripsForLocationListResponseDataListStatusLastKnownLocation(BaseModel): class TripsForLocationListResponseDataListStatusPosition(BaseModel): + """Current position of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the current position of the transit vehicle.""" diff --git a/src/onebusaway/types/trips_for_route_list_response.py b/src/onebusaway/types/trips_for_route_list_response.py index f9bc2d8..f373c34 100644 --- a/src/onebusaway/types/trips_for_route_list_response.py +++ b/src/onebusaway/types/trips_for_route_list_response.py @@ -47,6 +47,8 @@ class TripsForRouteListResponseDataListSchedule(BaseModel): class TripsForRouteListResponseDataListStatusLastKnownLocation(BaseModel): + """Last known location of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the last known location of the transit vehicle.""" @@ -55,6 +57,8 @@ class TripsForRouteListResponseDataListStatusLastKnownLocation(BaseModel): class TripsForRouteListResponseDataListStatusPosition(BaseModel): + """Current position of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the current position of the transit vehicle.""" diff --git a/src/onebusaway/types/vehicles_for_agency_list_response.py b/src/onebusaway/types/vehicles_for_agency_list_response.py index 34601dd..f40d3a9 100644 --- a/src/onebusaway/types/vehicles_for_agency_list_response.py +++ b/src/onebusaway/types/vehicles_for_agency_list_response.py @@ -26,6 +26,8 @@ class VehiclesForAgencyListResponseDataListLocation(BaseModel): class VehiclesForAgencyListResponseDataListTripStatusLastKnownLocation(BaseModel): + """Last known location of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the last known location of the transit vehicle.""" @@ -34,6 +36,8 @@ class VehiclesForAgencyListResponseDataListTripStatusLastKnownLocation(BaseModel class VehiclesForAgencyListResponseDataListTripStatusPosition(BaseModel): + """Current position of the transit vehicle.""" + lat: Optional[float] = None """Latitude of the current position of the transit vehicle.""" From 17442243ef6d3ca342ac4294de2257e59fdd7da4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 16 Dec 2025 05:20:48 +0000 Subject: [PATCH 13/18] chore(internal): add missing files argument to base client --- src/onebusaway/_base_client.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/onebusaway/_base_client.py b/src/onebusaway/_base_client.py index 2f2004e..99208e6 100644 --- a/src/onebusaway/_base_client.py +++ b/src/onebusaway/_base_client.py @@ -1247,9 +1247,12 @@ def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + opts = FinalRequestOptions.construct( + method="patch", url=path, json_data=body, files=to_httpx_files(files), **options + ) return self.request(cast_to, opts) def put( @@ -1767,9 +1770,12 @@ async def patch( *, cast_to: Type[ResponseT], body: Body | None = None, + files: RequestFiles | None = None, options: RequestOptions = {}, ) -> ResponseT: - opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options) + opts = FinalRequestOptions.construct( + method="patch", url=path, json_data=body, files=to_httpx_files(files), **options + ) return await self.request(cast_to, opts) async def put( From d938f6643cf144bb8db22d8c89024785ff5fdd97 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 17 Dec 2025 08:06:48 +0000 Subject: [PATCH 14/18] chore: speedup initial import --- src/onebusaway/_client.py | 1465 ++++++++++++++++++++++++++++--------- 1 file changed, 1100 insertions(+), 365 deletions(-) diff --git a/src/onebusaway/_client.py b/src/onebusaway/_client.py index 7688a85..5923bba 100644 --- a/src/onebusaway/_client.py +++ b/src/onebusaway/_client.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import Any, Mapping +from typing import TYPE_CHECKING, Any, Mapping from typing_extensions import Self, override import httpx @@ -20,37 +20,8 @@ not_given, ) from ._utils import is_given, get_async_library +from ._compat import cached_property from ._version import __version__ -from .resources import ( - stop, - trip, - block, - route, - shape, - agency, - config, - current_time, - trip_details, - search_for_stop, - stops_for_route, - trips_for_route, - search_for_route, - stops_for_agency, - trip_for_vehicle, - routes_for_agency, - schedule_for_stop, - schedule_for_route, - stops_for_location, - trips_for_location, - routes_for_location, - stop_ids_for_agency, - vehicles_for_agency, - route_ids_for_agency, - arrival_and_departure, - agencies_with_coverage, - report_problem_with_stop, - report_problem_with_trip, -) from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import APIStatusError, OnebusawaySDKError from ._base_client import ( @@ -59,6 +30,66 @@ AsyncAPIClient, ) +if TYPE_CHECKING: + from .resources import ( + stop, + trip, + block, + route, + shape, + agency, + config, + current_time, + trip_details, + search_for_stop, + stops_for_route, + trips_for_route, + search_for_route, + stops_for_agency, + trip_for_vehicle, + routes_for_agency, + schedule_for_stop, + schedule_for_route, + stops_for_location, + trips_for_location, + routes_for_location, + stop_ids_for_agency, + vehicles_for_agency, + route_ids_for_agency, + arrival_and_departure, + agencies_with_coverage, + report_problem_with_stop, + report_problem_with_trip, + ) + from .resources.stop import StopResource, AsyncStopResource + from .resources.trip import TripResource, AsyncTripResource + from .resources.block import BlockResource, AsyncBlockResource + from .resources.route import RouteResource, AsyncRouteResource + from .resources.shape import ShapeResource, AsyncShapeResource + from .resources.agency import AgencyResource, AsyncAgencyResource + from .resources.config import ConfigResource, AsyncConfigResource + from .resources.current_time import CurrentTimeResource, AsyncCurrentTimeResource + from .resources.trip_details import TripDetailsResource, AsyncTripDetailsResource + from .resources.search_for_stop import SearchForStopResource, AsyncSearchForStopResource + from .resources.stops_for_route import StopsForRouteResource, AsyncStopsForRouteResource + from .resources.trips_for_route import TripsForRouteResource, AsyncTripsForRouteResource + from .resources.search_for_route import SearchForRouteResource, AsyncSearchForRouteResource + from .resources.stops_for_agency import StopsForAgencyResource, AsyncStopsForAgencyResource + from .resources.trip_for_vehicle import TripForVehicleResource, AsyncTripForVehicleResource + from .resources.routes_for_agency import RoutesForAgencyResource, AsyncRoutesForAgencyResource + from .resources.schedule_for_stop import ScheduleForStopResource, AsyncScheduleForStopResource + from .resources.schedule_for_route import ScheduleForRouteResource, AsyncScheduleForRouteResource + from .resources.stops_for_location import StopsForLocationResource, AsyncStopsForLocationResource + from .resources.trips_for_location import TripsForLocationResource, AsyncTripsForLocationResource + from .resources.routes_for_location import RoutesForLocationResource, AsyncRoutesForLocationResource + from .resources.stop_ids_for_agency import StopIDsForAgencyResource, AsyncStopIDsForAgencyResource + from .resources.vehicles_for_agency import VehiclesForAgencyResource, AsyncVehiclesForAgencyResource + from .resources.route_ids_for_agency import RouteIDsForAgencyResource, AsyncRouteIDsForAgencyResource + from .resources.arrival_and_departure import ArrivalAndDepartureResource, AsyncArrivalAndDepartureResource + from .resources.agencies_with_coverage import AgenciesWithCoverageResource, AsyncAgenciesWithCoverageResource + from .resources.report_problem_with_stop import ReportProblemWithStopResource, AsyncReportProblemWithStopResource + from .resources.report_problem_with_trip import ReportProblemWithTripResource, AsyncReportProblemWithTripResource + __all__ = [ "Timeout", "Transport", @@ -72,37 +103,6 @@ class OnebusawaySDK(SyncAPIClient): - agencies_with_coverage: agencies_with_coverage.AgenciesWithCoverageResource - agency: agency.AgencyResource - vehicles_for_agency: vehicles_for_agency.VehiclesForAgencyResource - config: config.ConfigResource - current_time: current_time.CurrentTimeResource - stops_for_location: stops_for_location.StopsForLocationResource - stops_for_route: stops_for_route.StopsForRouteResource - stops_for_agency: stops_for_agency.StopsForAgencyResource - stop: stop.StopResource - stop_ids_for_agency: stop_ids_for_agency.StopIDsForAgencyResource - schedule_for_stop: schedule_for_stop.ScheduleForStopResource - route: route.RouteResource - route_ids_for_agency: route_ids_for_agency.RouteIDsForAgencyResource - routes_for_location: routes_for_location.RoutesForLocationResource - routes_for_agency: routes_for_agency.RoutesForAgencyResource - schedule_for_route: schedule_for_route.ScheduleForRouteResource - arrival_and_departure: arrival_and_departure.ArrivalAndDepartureResource - trip: trip.TripResource - trips_for_location: trips_for_location.TripsForLocationResource - trip_details: trip_details.TripDetailsResource - trip_for_vehicle: trip_for_vehicle.TripForVehicleResource - trips_for_route: trips_for_route.TripsForRouteResource - report_problem_with_stop: report_problem_with_stop.ReportProblemWithStopResource - report_problem_with_trip: report_problem_with_trip.ReportProblemWithTripResource - search_for_stop: search_for_stop.SearchForStopResource - search_for_route: search_for_route.SearchForRouteResource - block: block.BlockResource - shape: shape.ShapeResource - with_raw_response: OnebusawaySDKWithRawResponse - with_streaming_response: OnebusawaySDKWithStreamedResponse - # client options api_key: str @@ -157,36 +157,181 @@ def __init__( _strict_response_validation=_strict_response_validation, ) - self.agencies_with_coverage = agencies_with_coverage.AgenciesWithCoverageResource(self) - self.agency = agency.AgencyResource(self) - self.vehicles_for_agency = vehicles_for_agency.VehiclesForAgencyResource(self) - self.config = config.ConfigResource(self) - self.current_time = current_time.CurrentTimeResource(self) - self.stops_for_location = stops_for_location.StopsForLocationResource(self) - self.stops_for_route = stops_for_route.StopsForRouteResource(self) - self.stops_for_agency = stops_for_agency.StopsForAgencyResource(self) - self.stop = stop.StopResource(self) - self.stop_ids_for_agency = stop_ids_for_agency.StopIDsForAgencyResource(self) - self.schedule_for_stop = schedule_for_stop.ScheduleForStopResource(self) - self.route = route.RouteResource(self) - self.route_ids_for_agency = route_ids_for_agency.RouteIDsForAgencyResource(self) - self.routes_for_location = routes_for_location.RoutesForLocationResource(self) - self.routes_for_agency = routes_for_agency.RoutesForAgencyResource(self) - self.schedule_for_route = schedule_for_route.ScheduleForRouteResource(self) - self.arrival_and_departure = arrival_and_departure.ArrivalAndDepartureResource(self) - self.trip = trip.TripResource(self) - self.trips_for_location = trips_for_location.TripsForLocationResource(self) - self.trip_details = trip_details.TripDetailsResource(self) - self.trip_for_vehicle = trip_for_vehicle.TripForVehicleResource(self) - self.trips_for_route = trips_for_route.TripsForRouteResource(self) - self.report_problem_with_stop = report_problem_with_stop.ReportProblemWithStopResource(self) - self.report_problem_with_trip = report_problem_with_trip.ReportProblemWithTripResource(self) - self.search_for_stop = search_for_stop.SearchForStopResource(self) - self.search_for_route = search_for_route.SearchForRouteResource(self) - self.block = block.BlockResource(self) - self.shape = shape.ShapeResource(self) - self.with_raw_response = OnebusawaySDKWithRawResponse(self) - self.with_streaming_response = OnebusawaySDKWithStreamedResponse(self) + @cached_property + def agencies_with_coverage(self) -> AgenciesWithCoverageResource: + from .resources.agencies_with_coverage import AgenciesWithCoverageResource + + return AgenciesWithCoverageResource(self) + + @cached_property + def agency(self) -> AgencyResource: + from .resources.agency import AgencyResource + + return AgencyResource(self) + + @cached_property + def vehicles_for_agency(self) -> VehiclesForAgencyResource: + from .resources.vehicles_for_agency import VehiclesForAgencyResource + + return VehiclesForAgencyResource(self) + + @cached_property + def config(self) -> ConfigResource: + from .resources.config import ConfigResource + + return ConfigResource(self) + + @cached_property + def current_time(self) -> CurrentTimeResource: + from .resources.current_time import CurrentTimeResource + + return CurrentTimeResource(self) + + @cached_property + def stops_for_location(self) -> StopsForLocationResource: + from .resources.stops_for_location import StopsForLocationResource + + return StopsForLocationResource(self) + + @cached_property + def stops_for_route(self) -> StopsForRouteResource: + from .resources.stops_for_route import StopsForRouteResource + + return StopsForRouteResource(self) + + @cached_property + def stops_for_agency(self) -> StopsForAgencyResource: + from .resources.stops_for_agency import StopsForAgencyResource + + return StopsForAgencyResource(self) + + @cached_property + def stop(self) -> StopResource: + from .resources.stop import StopResource + + return StopResource(self) + + @cached_property + def stop_ids_for_agency(self) -> StopIDsForAgencyResource: + from .resources.stop_ids_for_agency import StopIDsForAgencyResource + + return StopIDsForAgencyResource(self) + + @cached_property + def schedule_for_stop(self) -> ScheduleForStopResource: + from .resources.schedule_for_stop import ScheduleForStopResource + + return ScheduleForStopResource(self) + + @cached_property + def route(self) -> RouteResource: + from .resources.route import RouteResource + + return RouteResource(self) + + @cached_property + def route_ids_for_agency(self) -> RouteIDsForAgencyResource: + from .resources.route_ids_for_agency import RouteIDsForAgencyResource + + return RouteIDsForAgencyResource(self) + + @cached_property + def routes_for_location(self) -> RoutesForLocationResource: + from .resources.routes_for_location import RoutesForLocationResource + + return RoutesForLocationResource(self) + + @cached_property + def routes_for_agency(self) -> RoutesForAgencyResource: + from .resources.routes_for_agency import RoutesForAgencyResource + + return RoutesForAgencyResource(self) + + @cached_property + def schedule_for_route(self) -> ScheduleForRouteResource: + from .resources.schedule_for_route import ScheduleForRouteResource + + return ScheduleForRouteResource(self) + + @cached_property + def arrival_and_departure(self) -> ArrivalAndDepartureResource: + from .resources.arrival_and_departure import ArrivalAndDepartureResource + + return ArrivalAndDepartureResource(self) + + @cached_property + def trip(self) -> TripResource: + from .resources.trip import TripResource + + return TripResource(self) + + @cached_property + def trips_for_location(self) -> TripsForLocationResource: + from .resources.trips_for_location import TripsForLocationResource + + return TripsForLocationResource(self) + + @cached_property + def trip_details(self) -> TripDetailsResource: + from .resources.trip_details import TripDetailsResource + + return TripDetailsResource(self) + + @cached_property + def trip_for_vehicle(self) -> TripForVehicleResource: + from .resources.trip_for_vehicle import TripForVehicleResource + + return TripForVehicleResource(self) + + @cached_property + def trips_for_route(self) -> TripsForRouteResource: + from .resources.trips_for_route import TripsForRouteResource + + return TripsForRouteResource(self) + + @cached_property + def report_problem_with_stop(self) -> ReportProblemWithStopResource: + from .resources.report_problem_with_stop import ReportProblemWithStopResource + + return ReportProblemWithStopResource(self) + + @cached_property + def report_problem_with_trip(self) -> ReportProblemWithTripResource: + from .resources.report_problem_with_trip import ReportProblemWithTripResource + + return ReportProblemWithTripResource(self) + + @cached_property + def search_for_stop(self) -> SearchForStopResource: + from .resources.search_for_stop import SearchForStopResource + + return SearchForStopResource(self) + + @cached_property + def search_for_route(self) -> SearchForRouteResource: + from .resources.search_for_route import SearchForRouteResource + + return SearchForRouteResource(self) + + @cached_property + def block(self) -> BlockResource: + from .resources.block import BlockResource + + return BlockResource(self) + + @cached_property + def shape(self) -> ShapeResource: + from .resources.shape import ShapeResource + + return ShapeResource(self) + + @cached_property + def with_raw_response(self) -> OnebusawaySDKWithRawResponse: + return OnebusawaySDKWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> OnebusawaySDKWithStreamedResponse: + return OnebusawaySDKWithStreamedResponse(self) @property @override @@ -305,37 +450,6 @@ def _make_status_error( class AsyncOnebusawaySDK(AsyncAPIClient): - agencies_with_coverage: agencies_with_coverage.AsyncAgenciesWithCoverageResource - agency: agency.AsyncAgencyResource - vehicles_for_agency: vehicles_for_agency.AsyncVehiclesForAgencyResource - config: config.AsyncConfigResource - current_time: current_time.AsyncCurrentTimeResource - stops_for_location: stops_for_location.AsyncStopsForLocationResource - stops_for_route: stops_for_route.AsyncStopsForRouteResource - stops_for_agency: stops_for_agency.AsyncStopsForAgencyResource - stop: stop.AsyncStopResource - stop_ids_for_agency: stop_ids_for_agency.AsyncStopIDsForAgencyResource - schedule_for_stop: schedule_for_stop.AsyncScheduleForStopResource - route: route.AsyncRouteResource - route_ids_for_agency: route_ids_for_agency.AsyncRouteIDsForAgencyResource - routes_for_location: routes_for_location.AsyncRoutesForLocationResource - routes_for_agency: routes_for_agency.AsyncRoutesForAgencyResource - schedule_for_route: schedule_for_route.AsyncScheduleForRouteResource - arrival_and_departure: arrival_and_departure.AsyncArrivalAndDepartureResource - trip: trip.AsyncTripResource - trips_for_location: trips_for_location.AsyncTripsForLocationResource - trip_details: trip_details.AsyncTripDetailsResource - trip_for_vehicle: trip_for_vehicle.AsyncTripForVehicleResource - trips_for_route: trips_for_route.AsyncTripsForRouteResource - report_problem_with_stop: report_problem_with_stop.AsyncReportProblemWithStopResource - report_problem_with_trip: report_problem_with_trip.AsyncReportProblemWithTripResource - search_for_stop: search_for_stop.AsyncSearchForStopResource - search_for_route: search_for_route.AsyncSearchForRouteResource - block: block.AsyncBlockResource - shape: shape.AsyncShapeResource - with_raw_response: AsyncOnebusawaySDKWithRawResponse - with_streaming_response: AsyncOnebusawaySDKWithStreamedResponse - # client options api_key: str @@ -390,36 +504,181 @@ def __init__( _strict_response_validation=_strict_response_validation, ) - self.agencies_with_coverage = agencies_with_coverage.AsyncAgenciesWithCoverageResource(self) - self.agency = agency.AsyncAgencyResource(self) - self.vehicles_for_agency = vehicles_for_agency.AsyncVehiclesForAgencyResource(self) - self.config = config.AsyncConfigResource(self) - self.current_time = current_time.AsyncCurrentTimeResource(self) - self.stops_for_location = stops_for_location.AsyncStopsForLocationResource(self) - self.stops_for_route = stops_for_route.AsyncStopsForRouteResource(self) - self.stops_for_agency = stops_for_agency.AsyncStopsForAgencyResource(self) - self.stop = stop.AsyncStopResource(self) - self.stop_ids_for_agency = stop_ids_for_agency.AsyncStopIDsForAgencyResource(self) - self.schedule_for_stop = schedule_for_stop.AsyncScheduleForStopResource(self) - self.route = route.AsyncRouteResource(self) - self.route_ids_for_agency = route_ids_for_agency.AsyncRouteIDsForAgencyResource(self) - self.routes_for_location = routes_for_location.AsyncRoutesForLocationResource(self) - self.routes_for_agency = routes_for_agency.AsyncRoutesForAgencyResource(self) - self.schedule_for_route = schedule_for_route.AsyncScheduleForRouteResource(self) - self.arrival_and_departure = arrival_and_departure.AsyncArrivalAndDepartureResource(self) - self.trip = trip.AsyncTripResource(self) - self.trips_for_location = trips_for_location.AsyncTripsForLocationResource(self) - self.trip_details = trip_details.AsyncTripDetailsResource(self) - self.trip_for_vehicle = trip_for_vehicle.AsyncTripForVehicleResource(self) - self.trips_for_route = trips_for_route.AsyncTripsForRouteResource(self) - self.report_problem_with_stop = report_problem_with_stop.AsyncReportProblemWithStopResource(self) - self.report_problem_with_trip = report_problem_with_trip.AsyncReportProblemWithTripResource(self) - self.search_for_stop = search_for_stop.AsyncSearchForStopResource(self) - self.search_for_route = search_for_route.AsyncSearchForRouteResource(self) - self.block = block.AsyncBlockResource(self) - self.shape = shape.AsyncShapeResource(self) - self.with_raw_response = AsyncOnebusawaySDKWithRawResponse(self) - self.with_streaming_response = AsyncOnebusawaySDKWithStreamedResponse(self) + @cached_property + def agencies_with_coverage(self) -> AsyncAgenciesWithCoverageResource: + from .resources.agencies_with_coverage import AsyncAgenciesWithCoverageResource + + return AsyncAgenciesWithCoverageResource(self) + + @cached_property + def agency(self) -> AsyncAgencyResource: + from .resources.agency import AsyncAgencyResource + + return AsyncAgencyResource(self) + + @cached_property + def vehicles_for_agency(self) -> AsyncVehiclesForAgencyResource: + from .resources.vehicles_for_agency import AsyncVehiclesForAgencyResource + + return AsyncVehiclesForAgencyResource(self) + + @cached_property + def config(self) -> AsyncConfigResource: + from .resources.config import AsyncConfigResource + + return AsyncConfigResource(self) + + @cached_property + def current_time(self) -> AsyncCurrentTimeResource: + from .resources.current_time import AsyncCurrentTimeResource + + return AsyncCurrentTimeResource(self) + + @cached_property + def stops_for_location(self) -> AsyncStopsForLocationResource: + from .resources.stops_for_location import AsyncStopsForLocationResource + + return AsyncStopsForLocationResource(self) + + @cached_property + def stops_for_route(self) -> AsyncStopsForRouteResource: + from .resources.stops_for_route import AsyncStopsForRouteResource + + return AsyncStopsForRouteResource(self) + + @cached_property + def stops_for_agency(self) -> AsyncStopsForAgencyResource: + from .resources.stops_for_agency import AsyncStopsForAgencyResource + + return AsyncStopsForAgencyResource(self) + + @cached_property + def stop(self) -> AsyncStopResource: + from .resources.stop import AsyncStopResource + + return AsyncStopResource(self) + + @cached_property + def stop_ids_for_agency(self) -> AsyncStopIDsForAgencyResource: + from .resources.stop_ids_for_agency import AsyncStopIDsForAgencyResource + + return AsyncStopIDsForAgencyResource(self) + + @cached_property + def schedule_for_stop(self) -> AsyncScheduleForStopResource: + from .resources.schedule_for_stop import AsyncScheduleForStopResource + + return AsyncScheduleForStopResource(self) + + @cached_property + def route(self) -> AsyncRouteResource: + from .resources.route import AsyncRouteResource + + return AsyncRouteResource(self) + + @cached_property + def route_ids_for_agency(self) -> AsyncRouteIDsForAgencyResource: + from .resources.route_ids_for_agency import AsyncRouteIDsForAgencyResource + + return AsyncRouteIDsForAgencyResource(self) + + @cached_property + def routes_for_location(self) -> AsyncRoutesForLocationResource: + from .resources.routes_for_location import AsyncRoutesForLocationResource + + return AsyncRoutesForLocationResource(self) + + @cached_property + def routes_for_agency(self) -> AsyncRoutesForAgencyResource: + from .resources.routes_for_agency import AsyncRoutesForAgencyResource + + return AsyncRoutesForAgencyResource(self) + + @cached_property + def schedule_for_route(self) -> AsyncScheduleForRouteResource: + from .resources.schedule_for_route import AsyncScheduleForRouteResource + + return AsyncScheduleForRouteResource(self) + + @cached_property + def arrival_and_departure(self) -> AsyncArrivalAndDepartureResource: + from .resources.arrival_and_departure import AsyncArrivalAndDepartureResource + + return AsyncArrivalAndDepartureResource(self) + + @cached_property + def trip(self) -> AsyncTripResource: + from .resources.trip import AsyncTripResource + + return AsyncTripResource(self) + + @cached_property + def trips_for_location(self) -> AsyncTripsForLocationResource: + from .resources.trips_for_location import AsyncTripsForLocationResource + + return AsyncTripsForLocationResource(self) + + @cached_property + def trip_details(self) -> AsyncTripDetailsResource: + from .resources.trip_details import AsyncTripDetailsResource + + return AsyncTripDetailsResource(self) + + @cached_property + def trip_for_vehicle(self) -> AsyncTripForVehicleResource: + from .resources.trip_for_vehicle import AsyncTripForVehicleResource + + return AsyncTripForVehicleResource(self) + + @cached_property + def trips_for_route(self) -> AsyncTripsForRouteResource: + from .resources.trips_for_route import AsyncTripsForRouteResource + + return AsyncTripsForRouteResource(self) + + @cached_property + def report_problem_with_stop(self) -> AsyncReportProblemWithStopResource: + from .resources.report_problem_with_stop import AsyncReportProblemWithStopResource + + return AsyncReportProblemWithStopResource(self) + + @cached_property + def report_problem_with_trip(self) -> AsyncReportProblemWithTripResource: + from .resources.report_problem_with_trip import AsyncReportProblemWithTripResource + + return AsyncReportProblemWithTripResource(self) + + @cached_property + def search_for_stop(self) -> AsyncSearchForStopResource: + from .resources.search_for_stop import AsyncSearchForStopResource + + return AsyncSearchForStopResource(self) + + @cached_property + def search_for_route(self) -> AsyncSearchForRouteResource: + from .resources.search_for_route import AsyncSearchForRouteResource + + return AsyncSearchForRouteResource(self) + + @cached_property + def block(self) -> AsyncBlockResource: + from .resources.block import AsyncBlockResource + + return AsyncBlockResource(self) + + @cached_property + def shape(self) -> AsyncShapeResource: + from .resources.shape import AsyncShapeResource + + return AsyncShapeResource(self) + + @cached_property + def with_raw_response(self) -> AsyncOnebusawaySDKWithRawResponse: + return AsyncOnebusawaySDKWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncOnebusawaySDKWithStreamedResponse: + return AsyncOnebusawaySDKWithStreamedResponse(self) @property @override @@ -538,231 +797,707 @@ def _make_status_error( class OnebusawaySDKWithRawResponse: + _client: OnebusawaySDK + def __init__(self, client: OnebusawaySDK) -> None: - self.agencies_with_coverage = agencies_with_coverage.AgenciesWithCoverageResourceWithRawResponse( - client.agencies_with_coverage - ) - self.agency = agency.AgencyResourceWithRawResponse(client.agency) - self.vehicles_for_agency = vehicles_for_agency.VehiclesForAgencyResourceWithRawResponse( - client.vehicles_for_agency - ) - self.config = config.ConfigResourceWithRawResponse(client.config) - self.current_time = current_time.CurrentTimeResourceWithRawResponse(client.current_time) - self.stops_for_location = stops_for_location.StopsForLocationResourceWithRawResponse(client.stops_for_location) - self.stops_for_route = stops_for_route.StopsForRouteResourceWithRawResponse(client.stops_for_route) - self.stops_for_agency = stops_for_agency.StopsForAgencyResourceWithRawResponse(client.stops_for_agency) - self.stop = stop.StopResourceWithRawResponse(client.stop) - self.stop_ids_for_agency = stop_ids_for_agency.StopIDsForAgencyResourceWithRawResponse( - client.stop_ids_for_agency - ) - self.schedule_for_stop = schedule_for_stop.ScheduleForStopResourceWithRawResponse(client.schedule_for_stop) - self.route = route.RouteResourceWithRawResponse(client.route) - self.route_ids_for_agency = route_ids_for_agency.RouteIDsForAgencyResourceWithRawResponse( - client.route_ids_for_agency - ) - self.routes_for_location = routes_for_location.RoutesForLocationResourceWithRawResponse( - client.routes_for_location - ) - self.routes_for_agency = routes_for_agency.RoutesForAgencyResourceWithRawResponse(client.routes_for_agency) - self.schedule_for_route = schedule_for_route.ScheduleForRouteResourceWithRawResponse(client.schedule_for_route) - self.arrival_and_departure = arrival_and_departure.ArrivalAndDepartureResourceWithRawResponse( - client.arrival_and_departure - ) - self.trip = trip.TripResourceWithRawResponse(client.trip) - self.trips_for_location = trips_for_location.TripsForLocationResourceWithRawResponse(client.trips_for_location) - self.trip_details = trip_details.TripDetailsResourceWithRawResponse(client.trip_details) - self.trip_for_vehicle = trip_for_vehicle.TripForVehicleResourceWithRawResponse(client.trip_for_vehicle) - self.trips_for_route = trips_for_route.TripsForRouteResourceWithRawResponse(client.trips_for_route) - self.report_problem_with_stop = report_problem_with_stop.ReportProblemWithStopResourceWithRawResponse( - client.report_problem_with_stop - ) - self.report_problem_with_trip = report_problem_with_trip.ReportProblemWithTripResourceWithRawResponse( - client.report_problem_with_trip - ) - self.search_for_stop = search_for_stop.SearchForStopResourceWithRawResponse(client.search_for_stop) - self.search_for_route = search_for_route.SearchForRouteResourceWithRawResponse(client.search_for_route) - self.block = block.BlockResourceWithRawResponse(client.block) - self.shape = shape.ShapeResourceWithRawResponse(client.shape) + self._client = client + + @cached_property + def agencies_with_coverage(self) -> agencies_with_coverage.AgenciesWithCoverageResourceWithRawResponse: + from .resources.agencies_with_coverage import AgenciesWithCoverageResourceWithRawResponse + + return AgenciesWithCoverageResourceWithRawResponse(self._client.agencies_with_coverage) + + @cached_property + def agency(self) -> agency.AgencyResourceWithRawResponse: + from .resources.agency import AgencyResourceWithRawResponse + + return AgencyResourceWithRawResponse(self._client.agency) + + @cached_property + def vehicles_for_agency(self) -> vehicles_for_agency.VehiclesForAgencyResourceWithRawResponse: + from .resources.vehicles_for_agency import VehiclesForAgencyResourceWithRawResponse + + return VehiclesForAgencyResourceWithRawResponse(self._client.vehicles_for_agency) + + @cached_property + def config(self) -> config.ConfigResourceWithRawResponse: + from .resources.config import ConfigResourceWithRawResponse + + return ConfigResourceWithRawResponse(self._client.config) + + @cached_property + def current_time(self) -> current_time.CurrentTimeResourceWithRawResponse: + from .resources.current_time import CurrentTimeResourceWithRawResponse + + return CurrentTimeResourceWithRawResponse(self._client.current_time) + + @cached_property + def stops_for_location(self) -> stops_for_location.StopsForLocationResourceWithRawResponse: + from .resources.stops_for_location import StopsForLocationResourceWithRawResponse + + return StopsForLocationResourceWithRawResponse(self._client.stops_for_location) + + @cached_property + def stops_for_route(self) -> stops_for_route.StopsForRouteResourceWithRawResponse: + from .resources.stops_for_route import StopsForRouteResourceWithRawResponse + + return StopsForRouteResourceWithRawResponse(self._client.stops_for_route) + + @cached_property + def stops_for_agency(self) -> stops_for_agency.StopsForAgencyResourceWithRawResponse: + from .resources.stops_for_agency import StopsForAgencyResourceWithRawResponse + + return StopsForAgencyResourceWithRawResponse(self._client.stops_for_agency) + + @cached_property + def stop(self) -> stop.StopResourceWithRawResponse: + from .resources.stop import StopResourceWithRawResponse + + return StopResourceWithRawResponse(self._client.stop) + + @cached_property + def stop_ids_for_agency(self) -> stop_ids_for_agency.StopIDsForAgencyResourceWithRawResponse: + from .resources.stop_ids_for_agency import StopIDsForAgencyResourceWithRawResponse + + return StopIDsForAgencyResourceWithRawResponse(self._client.stop_ids_for_agency) + + @cached_property + def schedule_for_stop(self) -> schedule_for_stop.ScheduleForStopResourceWithRawResponse: + from .resources.schedule_for_stop import ScheduleForStopResourceWithRawResponse + + return ScheduleForStopResourceWithRawResponse(self._client.schedule_for_stop) + + @cached_property + def route(self) -> route.RouteResourceWithRawResponse: + from .resources.route import RouteResourceWithRawResponse + + return RouteResourceWithRawResponse(self._client.route) + + @cached_property + def route_ids_for_agency(self) -> route_ids_for_agency.RouteIDsForAgencyResourceWithRawResponse: + from .resources.route_ids_for_agency import RouteIDsForAgencyResourceWithRawResponse + + return RouteIDsForAgencyResourceWithRawResponse(self._client.route_ids_for_agency) + + @cached_property + def routes_for_location(self) -> routes_for_location.RoutesForLocationResourceWithRawResponse: + from .resources.routes_for_location import RoutesForLocationResourceWithRawResponse + + return RoutesForLocationResourceWithRawResponse(self._client.routes_for_location) + + @cached_property + def routes_for_agency(self) -> routes_for_agency.RoutesForAgencyResourceWithRawResponse: + from .resources.routes_for_agency import RoutesForAgencyResourceWithRawResponse + + return RoutesForAgencyResourceWithRawResponse(self._client.routes_for_agency) + + @cached_property + def schedule_for_route(self) -> schedule_for_route.ScheduleForRouteResourceWithRawResponse: + from .resources.schedule_for_route import ScheduleForRouteResourceWithRawResponse + + return ScheduleForRouteResourceWithRawResponse(self._client.schedule_for_route) + + @cached_property + def arrival_and_departure(self) -> arrival_and_departure.ArrivalAndDepartureResourceWithRawResponse: + from .resources.arrival_and_departure import ArrivalAndDepartureResourceWithRawResponse + + return ArrivalAndDepartureResourceWithRawResponse(self._client.arrival_and_departure) + + @cached_property + def trip(self) -> trip.TripResourceWithRawResponse: + from .resources.trip import TripResourceWithRawResponse + + return TripResourceWithRawResponse(self._client.trip) + + @cached_property + def trips_for_location(self) -> trips_for_location.TripsForLocationResourceWithRawResponse: + from .resources.trips_for_location import TripsForLocationResourceWithRawResponse + + return TripsForLocationResourceWithRawResponse(self._client.trips_for_location) + + @cached_property + def trip_details(self) -> trip_details.TripDetailsResourceWithRawResponse: + from .resources.trip_details import TripDetailsResourceWithRawResponse + + return TripDetailsResourceWithRawResponse(self._client.trip_details) + + @cached_property + def trip_for_vehicle(self) -> trip_for_vehicle.TripForVehicleResourceWithRawResponse: + from .resources.trip_for_vehicle import TripForVehicleResourceWithRawResponse + + return TripForVehicleResourceWithRawResponse(self._client.trip_for_vehicle) + + @cached_property + def trips_for_route(self) -> trips_for_route.TripsForRouteResourceWithRawResponse: + from .resources.trips_for_route import TripsForRouteResourceWithRawResponse + + return TripsForRouteResourceWithRawResponse(self._client.trips_for_route) + + @cached_property + def report_problem_with_stop(self) -> report_problem_with_stop.ReportProblemWithStopResourceWithRawResponse: + from .resources.report_problem_with_stop import ReportProblemWithStopResourceWithRawResponse + + return ReportProblemWithStopResourceWithRawResponse(self._client.report_problem_with_stop) + + @cached_property + def report_problem_with_trip(self) -> report_problem_with_trip.ReportProblemWithTripResourceWithRawResponse: + from .resources.report_problem_with_trip import ReportProblemWithTripResourceWithRawResponse + + return ReportProblemWithTripResourceWithRawResponse(self._client.report_problem_with_trip) + + @cached_property + def search_for_stop(self) -> search_for_stop.SearchForStopResourceWithRawResponse: + from .resources.search_for_stop import SearchForStopResourceWithRawResponse + + return SearchForStopResourceWithRawResponse(self._client.search_for_stop) + + @cached_property + def search_for_route(self) -> search_for_route.SearchForRouteResourceWithRawResponse: + from .resources.search_for_route import SearchForRouteResourceWithRawResponse + + return SearchForRouteResourceWithRawResponse(self._client.search_for_route) + + @cached_property + def block(self) -> block.BlockResourceWithRawResponse: + from .resources.block import BlockResourceWithRawResponse + + return BlockResourceWithRawResponse(self._client.block) + + @cached_property + def shape(self) -> shape.ShapeResourceWithRawResponse: + from .resources.shape import ShapeResourceWithRawResponse + + return ShapeResourceWithRawResponse(self._client.shape) class AsyncOnebusawaySDKWithRawResponse: + _client: AsyncOnebusawaySDK + def __init__(self, client: AsyncOnebusawaySDK) -> None: - self.agencies_with_coverage = agencies_with_coverage.AsyncAgenciesWithCoverageResourceWithRawResponse( - client.agencies_with_coverage - ) - self.agency = agency.AsyncAgencyResourceWithRawResponse(client.agency) - self.vehicles_for_agency = vehicles_for_agency.AsyncVehiclesForAgencyResourceWithRawResponse( - client.vehicles_for_agency - ) - self.config = config.AsyncConfigResourceWithRawResponse(client.config) - self.current_time = current_time.AsyncCurrentTimeResourceWithRawResponse(client.current_time) - self.stops_for_location = stops_for_location.AsyncStopsForLocationResourceWithRawResponse( - client.stops_for_location - ) - self.stops_for_route = stops_for_route.AsyncStopsForRouteResourceWithRawResponse(client.stops_for_route) - self.stops_for_agency = stops_for_agency.AsyncStopsForAgencyResourceWithRawResponse(client.stops_for_agency) - self.stop = stop.AsyncStopResourceWithRawResponse(client.stop) - self.stop_ids_for_agency = stop_ids_for_agency.AsyncStopIDsForAgencyResourceWithRawResponse( - client.stop_ids_for_agency - ) - self.schedule_for_stop = schedule_for_stop.AsyncScheduleForStopResourceWithRawResponse(client.schedule_for_stop) - self.route = route.AsyncRouteResourceWithRawResponse(client.route) - self.route_ids_for_agency = route_ids_for_agency.AsyncRouteIDsForAgencyResourceWithRawResponse( - client.route_ids_for_agency - ) - self.routes_for_location = routes_for_location.AsyncRoutesForLocationResourceWithRawResponse( - client.routes_for_location - ) - self.routes_for_agency = routes_for_agency.AsyncRoutesForAgencyResourceWithRawResponse(client.routes_for_agency) - self.schedule_for_route = schedule_for_route.AsyncScheduleForRouteResourceWithRawResponse( - client.schedule_for_route - ) - self.arrival_and_departure = arrival_and_departure.AsyncArrivalAndDepartureResourceWithRawResponse( - client.arrival_and_departure - ) - self.trip = trip.AsyncTripResourceWithRawResponse(client.trip) - self.trips_for_location = trips_for_location.AsyncTripsForLocationResourceWithRawResponse( - client.trips_for_location - ) - self.trip_details = trip_details.AsyncTripDetailsResourceWithRawResponse(client.trip_details) - self.trip_for_vehicle = trip_for_vehicle.AsyncTripForVehicleResourceWithRawResponse(client.trip_for_vehicle) - self.trips_for_route = trips_for_route.AsyncTripsForRouteResourceWithRawResponse(client.trips_for_route) - self.report_problem_with_stop = report_problem_with_stop.AsyncReportProblemWithStopResourceWithRawResponse( - client.report_problem_with_stop - ) - self.report_problem_with_trip = report_problem_with_trip.AsyncReportProblemWithTripResourceWithRawResponse( - client.report_problem_with_trip - ) - self.search_for_stop = search_for_stop.AsyncSearchForStopResourceWithRawResponse(client.search_for_stop) - self.search_for_route = search_for_route.AsyncSearchForRouteResourceWithRawResponse(client.search_for_route) - self.block = block.AsyncBlockResourceWithRawResponse(client.block) - self.shape = shape.AsyncShapeResourceWithRawResponse(client.shape) + self._client = client + + @cached_property + def agencies_with_coverage(self) -> agencies_with_coverage.AsyncAgenciesWithCoverageResourceWithRawResponse: + from .resources.agencies_with_coverage import AsyncAgenciesWithCoverageResourceWithRawResponse + + return AsyncAgenciesWithCoverageResourceWithRawResponse(self._client.agencies_with_coverage) + + @cached_property + def agency(self) -> agency.AsyncAgencyResourceWithRawResponse: + from .resources.agency import AsyncAgencyResourceWithRawResponse + + return AsyncAgencyResourceWithRawResponse(self._client.agency) + + @cached_property + def vehicles_for_agency(self) -> vehicles_for_agency.AsyncVehiclesForAgencyResourceWithRawResponse: + from .resources.vehicles_for_agency import AsyncVehiclesForAgencyResourceWithRawResponse + + return AsyncVehiclesForAgencyResourceWithRawResponse(self._client.vehicles_for_agency) + + @cached_property + def config(self) -> config.AsyncConfigResourceWithRawResponse: + from .resources.config import AsyncConfigResourceWithRawResponse + + return AsyncConfigResourceWithRawResponse(self._client.config) + + @cached_property + def current_time(self) -> current_time.AsyncCurrentTimeResourceWithRawResponse: + from .resources.current_time import AsyncCurrentTimeResourceWithRawResponse + + return AsyncCurrentTimeResourceWithRawResponse(self._client.current_time) + + @cached_property + def stops_for_location(self) -> stops_for_location.AsyncStopsForLocationResourceWithRawResponse: + from .resources.stops_for_location import AsyncStopsForLocationResourceWithRawResponse + + return AsyncStopsForLocationResourceWithRawResponse(self._client.stops_for_location) + + @cached_property + def stops_for_route(self) -> stops_for_route.AsyncStopsForRouteResourceWithRawResponse: + from .resources.stops_for_route import AsyncStopsForRouteResourceWithRawResponse + + return AsyncStopsForRouteResourceWithRawResponse(self._client.stops_for_route) + + @cached_property + def stops_for_agency(self) -> stops_for_agency.AsyncStopsForAgencyResourceWithRawResponse: + from .resources.stops_for_agency import AsyncStopsForAgencyResourceWithRawResponse + + return AsyncStopsForAgencyResourceWithRawResponse(self._client.stops_for_agency) + + @cached_property + def stop(self) -> stop.AsyncStopResourceWithRawResponse: + from .resources.stop import AsyncStopResourceWithRawResponse + + return AsyncStopResourceWithRawResponse(self._client.stop) + + @cached_property + def stop_ids_for_agency(self) -> stop_ids_for_agency.AsyncStopIDsForAgencyResourceWithRawResponse: + from .resources.stop_ids_for_agency import AsyncStopIDsForAgencyResourceWithRawResponse + + return AsyncStopIDsForAgencyResourceWithRawResponse(self._client.stop_ids_for_agency) + + @cached_property + def schedule_for_stop(self) -> schedule_for_stop.AsyncScheduleForStopResourceWithRawResponse: + from .resources.schedule_for_stop import AsyncScheduleForStopResourceWithRawResponse + + return AsyncScheduleForStopResourceWithRawResponse(self._client.schedule_for_stop) + + @cached_property + def route(self) -> route.AsyncRouteResourceWithRawResponse: + from .resources.route import AsyncRouteResourceWithRawResponse + + return AsyncRouteResourceWithRawResponse(self._client.route) + + @cached_property + def route_ids_for_agency(self) -> route_ids_for_agency.AsyncRouteIDsForAgencyResourceWithRawResponse: + from .resources.route_ids_for_agency import AsyncRouteIDsForAgencyResourceWithRawResponse + + return AsyncRouteIDsForAgencyResourceWithRawResponse(self._client.route_ids_for_agency) + + @cached_property + def routes_for_location(self) -> routes_for_location.AsyncRoutesForLocationResourceWithRawResponse: + from .resources.routes_for_location import AsyncRoutesForLocationResourceWithRawResponse + + return AsyncRoutesForLocationResourceWithRawResponse(self._client.routes_for_location) + + @cached_property + def routes_for_agency(self) -> routes_for_agency.AsyncRoutesForAgencyResourceWithRawResponse: + from .resources.routes_for_agency import AsyncRoutesForAgencyResourceWithRawResponse + + return AsyncRoutesForAgencyResourceWithRawResponse(self._client.routes_for_agency) + + @cached_property + def schedule_for_route(self) -> schedule_for_route.AsyncScheduleForRouteResourceWithRawResponse: + from .resources.schedule_for_route import AsyncScheduleForRouteResourceWithRawResponse + + return AsyncScheduleForRouteResourceWithRawResponse(self._client.schedule_for_route) + + @cached_property + def arrival_and_departure(self) -> arrival_and_departure.AsyncArrivalAndDepartureResourceWithRawResponse: + from .resources.arrival_and_departure import AsyncArrivalAndDepartureResourceWithRawResponse + + return AsyncArrivalAndDepartureResourceWithRawResponse(self._client.arrival_and_departure) + + @cached_property + def trip(self) -> trip.AsyncTripResourceWithRawResponse: + from .resources.trip import AsyncTripResourceWithRawResponse + + return AsyncTripResourceWithRawResponse(self._client.trip) + + @cached_property + def trips_for_location(self) -> trips_for_location.AsyncTripsForLocationResourceWithRawResponse: + from .resources.trips_for_location import AsyncTripsForLocationResourceWithRawResponse + + return AsyncTripsForLocationResourceWithRawResponse(self._client.trips_for_location) + + @cached_property + def trip_details(self) -> trip_details.AsyncTripDetailsResourceWithRawResponse: + from .resources.trip_details import AsyncTripDetailsResourceWithRawResponse + + return AsyncTripDetailsResourceWithRawResponse(self._client.trip_details) + + @cached_property + def trip_for_vehicle(self) -> trip_for_vehicle.AsyncTripForVehicleResourceWithRawResponse: + from .resources.trip_for_vehicle import AsyncTripForVehicleResourceWithRawResponse + + return AsyncTripForVehicleResourceWithRawResponse(self._client.trip_for_vehicle) + + @cached_property + def trips_for_route(self) -> trips_for_route.AsyncTripsForRouteResourceWithRawResponse: + from .resources.trips_for_route import AsyncTripsForRouteResourceWithRawResponse + + return AsyncTripsForRouteResourceWithRawResponse(self._client.trips_for_route) + + @cached_property + def report_problem_with_stop(self) -> report_problem_with_stop.AsyncReportProblemWithStopResourceWithRawResponse: + from .resources.report_problem_with_stop import AsyncReportProblemWithStopResourceWithRawResponse + + return AsyncReportProblemWithStopResourceWithRawResponse(self._client.report_problem_with_stop) + + @cached_property + def report_problem_with_trip(self) -> report_problem_with_trip.AsyncReportProblemWithTripResourceWithRawResponse: + from .resources.report_problem_with_trip import AsyncReportProblemWithTripResourceWithRawResponse + + return AsyncReportProblemWithTripResourceWithRawResponse(self._client.report_problem_with_trip) + + @cached_property + def search_for_stop(self) -> search_for_stop.AsyncSearchForStopResourceWithRawResponse: + from .resources.search_for_stop import AsyncSearchForStopResourceWithRawResponse + + return AsyncSearchForStopResourceWithRawResponse(self._client.search_for_stop) + + @cached_property + def search_for_route(self) -> search_for_route.AsyncSearchForRouteResourceWithRawResponse: + from .resources.search_for_route import AsyncSearchForRouteResourceWithRawResponse + + return AsyncSearchForRouteResourceWithRawResponse(self._client.search_for_route) + + @cached_property + def block(self) -> block.AsyncBlockResourceWithRawResponse: + from .resources.block import AsyncBlockResourceWithRawResponse + + return AsyncBlockResourceWithRawResponse(self._client.block) + + @cached_property + def shape(self) -> shape.AsyncShapeResourceWithRawResponse: + from .resources.shape import AsyncShapeResourceWithRawResponse + + return AsyncShapeResourceWithRawResponse(self._client.shape) class OnebusawaySDKWithStreamedResponse: + _client: OnebusawaySDK + def __init__(self, client: OnebusawaySDK) -> None: - self.agencies_with_coverage = agencies_with_coverage.AgenciesWithCoverageResourceWithStreamingResponse( - client.agencies_with_coverage - ) - self.agency = agency.AgencyResourceWithStreamingResponse(client.agency) - self.vehicles_for_agency = vehicles_for_agency.VehiclesForAgencyResourceWithStreamingResponse( - client.vehicles_for_agency - ) - self.config = config.ConfigResourceWithStreamingResponse(client.config) - self.current_time = current_time.CurrentTimeResourceWithStreamingResponse(client.current_time) - self.stops_for_location = stops_for_location.StopsForLocationResourceWithStreamingResponse( - client.stops_for_location - ) - self.stops_for_route = stops_for_route.StopsForRouteResourceWithStreamingResponse(client.stops_for_route) - self.stops_for_agency = stops_for_agency.StopsForAgencyResourceWithStreamingResponse(client.stops_for_agency) - self.stop = stop.StopResourceWithStreamingResponse(client.stop) - self.stop_ids_for_agency = stop_ids_for_agency.StopIDsForAgencyResourceWithStreamingResponse( - client.stop_ids_for_agency - ) - self.schedule_for_stop = schedule_for_stop.ScheduleForStopResourceWithStreamingResponse( - client.schedule_for_stop - ) - self.route = route.RouteResourceWithStreamingResponse(client.route) - self.route_ids_for_agency = route_ids_for_agency.RouteIDsForAgencyResourceWithStreamingResponse( - client.route_ids_for_agency - ) - self.routes_for_location = routes_for_location.RoutesForLocationResourceWithStreamingResponse( - client.routes_for_location - ) - self.routes_for_agency = routes_for_agency.RoutesForAgencyResourceWithStreamingResponse( - client.routes_for_agency - ) - self.schedule_for_route = schedule_for_route.ScheduleForRouteResourceWithStreamingResponse( - client.schedule_for_route - ) - self.arrival_and_departure = arrival_and_departure.ArrivalAndDepartureResourceWithStreamingResponse( - client.arrival_and_departure - ) - self.trip = trip.TripResourceWithStreamingResponse(client.trip) - self.trips_for_location = trips_for_location.TripsForLocationResourceWithStreamingResponse( - client.trips_for_location - ) - self.trip_details = trip_details.TripDetailsResourceWithStreamingResponse(client.trip_details) - self.trip_for_vehicle = trip_for_vehicle.TripForVehicleResourceWithStreamingResponse(client.trip_for_vehicle) - self.trips_for_route = trips_for_route.TripsForRouteResourceWithStreamingResponse(client.trips_for_route) - self.report_problem_with_stop = report_problem_with_stop.ReportProblemWithStopResourceWithStreamingResponse( - client.report_problem_with_stop - ) - self.report_problem_with_trip = report_problem_with_trip.ReportProblemWithTripResourceWithStreamingResponse( - client.report_problem_with_trip - ) - self.search_for_stop = search_for_stop.SearchForStopResourceWithStreamingResponse(client.search_for_stop) - self.search_for_route = search_for_route.SearchForRouteResourceWithStreamingResponse(client.search_for_route) - self.block = block.BlockResourceWithStreamingResponse(client.block) - self.shape = shape.ShapeResourceWithStreamingResponse(client.shape) + self._client = client + + @cached_property + def agencies_with_coverage(self) -> agencies_with_coverage.AgenciesWithCoverageResourceWithStreamingResponse: + from .resources.agencies_with_coverage import AgenciesWithCoverageResourceWithStreamingResponse + + return AgenciesWithCoverageResourceWithStreamingResponse(self._client.agencies_with_coverage) + + @cached_property + def agency(self) -> agency.AgencyResourceWithStreamingResponse: + from .resources.agency import AgencyResourceWithStreamingResponse + + return AgencyResourceWithStreamingResponse(self._client.agency) + + @cached_property + def vehicles_for_agency(self) -> vehicles_for_agency.VehiclesForAgencyResourceWithStreamingResponse: + from .resources.vehicles_for_agency import VehiclesForAgencyResourceWithStreamingResponse + + return VehiclesForAgencyResourceWithStreamingResponse(self._client.vehicles_for_agency) + + @cached_property + def config(self) -> config.ConfigResourceWithStreamingResponse: + from .resources.config import ConfigResourceWithStreamingResponse + + return ConfigResourceWithStreamingResponse(self._client.config) + + @cached_property + def current_time(self) -> current_time.CurrentTimeResourceWithStreamingResponse: + from .resources.current_time import CurrentTimeResourceWithStreamingResponse + + return CurrentTimeResourceWithStreamingResponse(self._client.current_time) + + @cached_property + def stops_for_location(self) -> stops_for_location.StopsForLocationResourceWithStreamingResponse: + from .resources.stops_for_location import StopsForLocationResourceWithStreamingResponse + + return StopsForLocationResourceWithStreamingResponse(self._client.stops_for_location) + + @cached_property + def stops_for_route(self) -> stops_for_route.StopsForRouteResourceWithStreamingResponse: + from .resources.stops_for_route import StopsForRouteResourceWithStreamingResponse + + return StopsForRouteResourceWithStreamingResponse(self._client.stops_for_route) + + @cached_property + def stops_for_agency(self) -> stops_for_agency.StopsForAgencyResourceWithStreamingResponse: + from .resources.stops_for_agency import StopsForAgencyResourceWithStreamingResponse + + return StopsForAgencyResourceWithStreamingResponse(self._client.stops_for_agency) + + @cached_property + def stop(self) -> stop.StopResourceWithStreamingResponse: + from .resources.stop import StopResourceWithStreamingResponse + + return StopResourceWithStreamingResponse(self._client.stop) + + @cached_property + def stop_ids_for_agency(self) -> stop_ids_for_agency.StopIDsForAgencyResourceWithStreamingResponse: + from .resources.stop_ids_for_agency import StopIDsForAgencyResourceWithStreamingResponse + + return StopIDsForAgencyResourceWithStreamingResponse(self._client.stop_ids_for_agency) + + @cached_property + def schedule_for_stop(self) -> schedule_for_stop.ScheduleForStopResourceWithStreamingResponse: + from .resources.schedule_for_stop import ScheduleForStopResourceWithStreamingResponse + + return ScheduleForStopResourceWithStreamingResponse(self._client.schedule_for_stop) + + @cached_property + def route(self) -> route.RouteResourceWithStreamingResponse: + from .resources.route import RouteResourceWithStreamingResponse + + return RouteResourceWithStreamingResponse(self._client.route) + + @cached_property + def route_ids_for_agency(self) -> route_ids_for_agency.RouteIDsForAgencyResourceWithStreamingResponse: + from .resources.route_ids_for_agency import RouteIDsForAgencyResourceWithStreamingResponse + + return RouteIDsForAgencyResourceWithStreamingResponse(self._client.route_ids_for_agency) + + @cached_property + def routes_for_location(self) -> routes_for_location.RoutesForLocationResourceWithStreamingResponse: + from .resources.routes_for_location import RoutesForLocationResourceWithStreamingResponse + + return RoutesForLocationResourceWithStreamingResponse(self._client.routes_for_location) + + @cached_property + def routes_for_agency(self) -> routes_for_agency.RoutesForAgencyResourceWithStreamingResponse: + from .resources.routes_for_agency import RoutesForAgencyResourceWithStreamingResponse + + return RoutesForAgencyResourceWithStreamingResponse(self._client.routes_for_agency) + + @cached_property + def schedule_for_route(self) -> schedule_for_route.ScheduleForRouteResourceWithStreamingResponse: + from .resources.schedule_for_route import ScheduleForRouteResourceWithStreamingResponse + + return ScheduleForRouteResourceWithStreamingResponse(self._client.schedule_for_route) + + @cached_property + def arrival_and_departure(self) -> arrival_and_departure.ArrivalAndDepartureResourceWithStreamingResponse: + from .resources.arrival_and_departure import ArrivalAndDepartureResourceWithStreamingResponse + + return ArrivalAndDepartureResourceWithStreamingResponse(self._client.arrival_and_departure) + + @cached_property + def trip(self) -> trip.TripResourceWithStreamingResponse: + from .resources.trip import TripResourceWithStreamingResponse + + return TripResourceWithStreamingResponse(self._client.trip) + + @cached_property + def trips_for_location(self) -> trips_for_location.TripsForLocationResourceWithStreamingResponse: + from .resources.trips_for_location import TripsForLocationResourceWithStreamingResponse + + return TripsForLocationResourceWithStreamingResponse(self._client.trips_for_location) + + @cached_property + def trip_details(self) -> trip_details.TripDetailsResourceWithStreamingResponse: + from .resources.trip_details import TripDetailsResourceWithStreamingResponse + + return TripDetailsResourceWithStreamingResponse(self._client.trip_details) + + @cached_property + def trip_for_vehicle(self) -> trip_for_vehicle.TripForVehicleResourceWithStreamingResponse: + from .resources.trip_for_vehicle import TripForVehicleResourceWithStreamingResponse + + return TripForVehicleResourceWithStreamingResponse(self._client.trip_for_vehicle) + + @cached_property + def trips_for_route(self) -> trips_for_route.TripsForRouteResourceWithStreamingResponse: + from .resources.trips_for_route import TripsForRouteResourceWithStreamingResponse + + return TripsForRouteResourceWithStreamingResponse(self._client.trips_for_route) + + @cached_property + def report_problem_with_stop(self) -> report_problem_with_stop.ReportProblemWithStopResourceWithStreamingResponse: + from .resources.report_problem_with_stop import ReportProblemWithStopResourceWithStreamingResponse + + return ReportProblemWithStopResourceWithStreamingResponse(self._client.report_problem_with_stop) + + @cached_property + def report_problem_with_trip(self) -> report_problem_with_trip.ReportProblemWithTripResourceWithStreamingResponse: + from .resources.report_problem_with_trip import ReportProblemWithTripResourceWithStreamingResponse + + return ReportProblemWithTripResourceWithStreamingResponse(self._client.report_problem_with_trip) + + @cached_property + def search_for_stop(self) -> search_for_stop.SearchForStopResourceWithStreamingResponse: + from .resources.search_for_stop import SearchForStopResourceWithStreamingResponse + + return SearchForStopResourceWithStreamingResponse(self._client.search_for_stop) + + @cached_property + def search_for_route(self) -> search_for_route.SearchForRouteResourceWithStreamingResponse: + from .resources.search_for_route import SearchForRouteResourceWithStreamingResponse + + return SearchForRouteResourceWithStreamingResponse(self._client.search_for_route) + + @cached_property + def block(self) -> block.BlockResourceWithStreamingResponse: + from .resources.block import BlockResourceWithStreamingResponse + + return BlockResourceWithStreamingResponse(self._client.block) + + @cached_property + def shape(self) -> shape.ShapeResourceWithStreamingResponse: + from .resources.shape import ShapeResourceWithStreamingResponse + + return ShapeResourceWithStreamingResponse(self._client.shape) class AsyncOnebusawaySDKWithStreamedResponse: + _client: AsyncOnebusawaySDK + def __init__(self, client: AsyncOnebusawaySDK) -> None: - self.agencies_with_coverage = agencies_with_coverage.AsyncAgenciesWithCoverageResourceWithStreamingResponse( - client.agencies_with_coverage - ) - self.agency = agency.AsyncAgencyResourceWithStreamingResponse(client.agency) - self.vehicles_for_agency = vehicles_for_agency.AsyncVehiclesForAgencyResourceWithStreamingResponse( - client.vehicles_for_agency - ) - self.config = config.AsyncConfigResourceWithStreamingResponse(client.config) - self.current_time = current_time.AsyncCurrentTimeResourceWithStreamingResponse(client.current_time) - self.stops_for_location = stops_for_location.AsyncStopsForLocationResourceWithStreamingResponse( - client.stops_for_location - ) - self.stops_for_route = stops_for_route.AsyncStopsForRouteResourceWithStreamingResponse(client.stops_for_route) - self.stops_for_agency = stops_for_agency.AsyncStopsForAgencyResourceWithStreamingResponse( - client.stops_for_agency - ) - self.stop = stop.AsyncStopResourceWithStreamingResponse(client.stop) - self.stop_ids_for_agency = stop_ids_for_agency.AsyncStopIDsForAgencyResourceWithStreamingResponse( - client.stop_ids_for_agency - ) - self.schedule_for_stop = schedule_for_stop.AsyncScheduleForStopResourceWithStreamingResponse( - client.schedule_for_stop - ) - self.route = route.AsyncRouteResourceWithStreamingResponse(client.route) - self.route_ids_for_agency = route_ids_for_agency.AsyncRouteIDsForAgencyResourceWithStreamingResponse( - client.route_ids_for_agency - ) - self.routes_for_location = routes_for_location.AsyncRoutesForLocationResourceWithStreamingResponse( - client.routes_for_location - ) - self.routes_for_agency = routes_for_agency.AsyncRoutesForAgencyResourceWithStreamingResponse( - client.routes_for_agency - ) - self.schedule_for_route = schedule_for_route.AsyncScheduleForRouteResourceWithStreamingResponse( - client.schedule_for_route - ) - self.arrival_and_departure = arrival_and_departure.AsyncArrivalAndDepartureResourceWithStreamingResponse( - client.arrival_and_departure - ) - self.trip = trip.AsyncTripResourceWithStreamingResponse(client.trip) - self.trips_for_location = trips_for_location.AsyncTripsForLocationResourceWithStreamingResponse( - client.trips_for_location - ) - self.trip_details = trip_details.AsyncTripDetailsResourceWithStreamingResponse(client.trip_details) - self.trip_for_vehicle = trip_for_vehicle.AsyncTripForVehicleResourceWithStreamingResponse( - client.trip_for_vehicle - ) - self.trips_for_route = trips_for_route.AsyncTripsForRouteResourceWithStreamingResponse(client.trips_for_route) - self.report_problem_with_stop = ( - report_problem_with_stop.AsyncReportProblemWithStopResourceWithStreamingResponse( - client.report_problem_with_stop - ) - ) - self.report_problem_with_trip = ( - report_problem_with_trip.AsyncReportProblemWithTripResourceWithStreamingResponse( - client.report_problem_with_trip - ) - ) - self.search_for_stop = search_for_stop.AsyncSearchForStopResourceWithStreamingResponse(client.search_for_stop) - self.search_for_route = search_for_route.AsyncSearchForRouteResourceWithStreamingResponse( - client.search_for_route - ) - self.block = block.AsyncBlockResourceWithStreamingResponse(client.block) - self.shape = shape.AsyncShapeResourceWithStreamingResponse(client.shape) + self._client = client + + @cached_property + def agencies_with_coverage(self) -> agencies_with_coverage.AsyncAgenciesWithCoverageResourceWithStreamingResponse: + from .resources.agencies_with_coverage import AsyncAgenciesWithCoverageResourceWithStreamingResponse + + return AsyncAgenciesWithCoverageResourceWithStreamingResponse(self._client.agencies_with_coverage) + + @cached_property + def agency(self) -> agency.AsyncAgencyResourceWithStreamingResponse: + from .resources.agency import AsyncAgencyResourceWithStreamingResponse + + return AsyncAgencyResourceWithStreamingResponse(self._client.agency) + + @cached_property + def vehicles_for_agency(self) -> vehicles_for_agency.AsyncVehiclesForAgencyResourceWithStreamingResponse: + from .resources.vehicles_for_agency import AsyncVehiclesForAgencyResourceWithStreamingResponse + + return AsyncVehiclesForAgencyResourceWithStreamingResponse(self._client.vehicles_for_agency) + + @cached_property + def config(self) -> config.AsyncConfigResourceWithStreamingResponse: + from .resources.config import AsyncConfigResourceWithStreamingResponse + + return AsyncConfigResourceWithStreamingResponse(self._client.config) + + @cached_property + def current_time(self) -> current_time.AsyncCurrentTimeResourceWithStreamingResponse: + from .resources.current_time import AsyncCurrentTimeResourceWithStreamingResponse + + return AsyncCurrentTimeResourceWithStreamingResponse(self._client.current_time) + + @cached_property + def stops_for_location(self) -> stops_for_location.AsyncStopsForLocationResourceWithStreamingResponse: + from .resources.stops_for_location import AsyncStopsForLocationResourceWithStreamingResponse + + return AsyncStopsForLocationResourceWithStreamingResponse(self._client.stops_for_location) + + @cached_property + def stops_for_route(self) -> stops_for_route.AsyncStopsForRouteResourceWithStreamingResponse: + from .resources.stops_for_route import AsyncStopsForRouteResourceWithStreamingResponse + + return AsyncStopsForRouteResourceWithStreamingResponse(self._client.stops_for_route) + + @cached_property + def stops_for_agency(self) -> stops_for_agency.AsyncStopsForAgencyResourceWithStreamingResponse: + from .resources.stops_for_agency import AsyncStopsForAgencyResourceWithStreamingResponse + + return AsyncStopsForAgencyResourceWithStreamingResponse(self._client.stops_for_agency) + + @cached_property + def stop(self) -> stop.AsyncStopResourceWithStreamingResponse: + from .resources.stop import AsyncStopResourceWithStreamingResponse + + return AsyncStopResourceWithStreamingResponse(self._client.stop) + + @cached_property + def stop_ids_for_agency(self) -> stop_ids_for_agency.AsyncStopIDsForAgencyResourceWithStreamingResponse: + from .resources.stop_ids_for_agency import AsyncStopIDsForAgencyResourceWithStreamingResponse + + return AsyncStopIDsForAgencyResourceWithStreamingResponse(self._client.stop_ids_for_agency) + + @cached_property + def schedule_for_stop(self) -> schedule_for_stop.AsyncScheduleForStopResourceWithStreamingResponse: + from .resources.schedule_for_stop import AsyncScheduleForStopResourceWithStreamingResponse + + return AsyncScheduleForStopResourceWithStreamingResponse(self._client.schedule_for_stop) + + @cached_property + def route(self) -> route.AsyncRouteResourceWithStreamingResponse: + from .resources.route import AsyncRouteResourceWithStreamingResponse + + return AsyncRouteResourceWithStreamingResponse(self._client.route) + + @cached_property + def route_ids_for_agency(self) -> route_ids_for_agency.AsyncRouteIDsForAgencyResourceWithStreamingResponse: + from .resources.route_ids_for_agency import AsyncRouteIDsForAgencyResourceWithStreamingResponse + + return AsyncRouteIDsForAgencyResourceWithStreamingResponse(self._client.route_ids_for_agency) + + @cached_property + def routes_for_location(self) -> routes_for_location.AsyncRoutesForLocationResourceWithStreamingResponse: + from .resources.routes_for_location import AsyncRoutesForLocationResourceWithStreamingResponse + + return AsyncRoutesForLocationResourceWithStreamingResponse(self._client.routes_for_location) + + @cached_property + def routes_for_agency(self) -> routes_for_agency.AsyncRoutesForAgencyResourceWithStreamingResponse: + from .resources.routes_for_agency import AsyncRoutesForAgencyResourceWithStreamingResponse + + return AsyncRoutesForAgencyResourceWithStreamingResponse(self._client.routes_for_agency) + + @cached_property + def schedule_for_route(self) -> schedule_for_route.AsyncScheduleForRouteResourceWithStreamingResponse: + from .resources.schedule_for_route import AsyncScheduleForRouteResourceWithStreamingResponse + + return AsyncScheduleForRouteResourceWithStreamingResponse(self._client.schedule_for_route) + + @cached_property + def arrival_and_departure(self) -> arrival_and_departure.AsyncArrivalAndDepartureResourceWithStreamingResponse: + from .resources.arrival_and_departure import AsyncArrivalAndDepartureResourceWithStreamingResponse + + return AsyncArrivalAndDepartureResourceWithStreamingResponse(self._client.arrival_and_departure) + + @cached_property + def trip(self) -> trip.AsyncTripResourceWithStreamingResponse: + from .resources.trip import AsyncTripResourceWithStreamingResponse + + return AsyncTripResourceWithStreamingResponse(self._client.trip) + + @cached_property + def trips_for_location(self) -> trips_for_location.AsyncTripsForLocationResourceWithStreamingResponse: + from .resources.trips_for_location import AsyncTripsForLocationResourceWithStreamingResponse + + return AsyncTripsForLocationResourceWithStreamingResponse(self._client.trips_for_location) + + @cached_property + def trip_details(self) -> trip_details.AsyncTripDetailsResourceWithStreamingResponse: + from .resources.trip_details import AsyncTripDetailsResourceWithStreamingResponse + + return AsyncTripDetailsResourceWithStreamingResponse(self._client.trip_details) + + @cached_property + def trip_for_vehicle(self) -> trip_for_vehicle.AsyncTripForVehicleResourceWithStreamingResponse: + from .resources.trip_for_vehicle import AsyncTripForVehicleResourceWithStreamingResponse + + return AsyncTripForVehicleResourceWithStreamingResponse(self._client.trip_for_vehicle) + + @cached_property + def trips_for_route(self) -> trips_for_route.AsyncTripsForRouteResourceWithStreamingResponse: + from .resources.trips_for_route import AsyncTripsForRouteResourceWithStreamingResponse + + return AsyncTripsForRouteResourceWithStreamingResponse(self._client.trips_for_route) + + @cached_property + def report_problem_with_stop( + self, + ) -> report_problem_with_stop.AsyncReportProblemWithStopResourceWithStreamingResponse: + from .resources.report_problem_with_stop import AsyncReportProblemWithStopResourceWithStreamingResponse + + return AsyncReportProblemWithStopResourceWithStreamingResponse(self._client.report_problem_with_stop) + + @cached_property + def report_problem_with_trip( + self, + ) -> report_problem_with_trip.AsyncReportProblemWithTripResourceWithStreamingResponse: + from .resources.report_problem_with_trip import AsyncReportProblemWithTripResourceWithStreamingResponse + + return AsyncReportProblemWithTripResourceWithStreamingResponse(self._client.report_problem_with_trip) + + @cached_property + def search_for_stop(self) -> search_for_stop.AsyncSearchForStopResourceWithStreamingResponse: + from .resources.search_for_stop import AsyncSearchForStopResourceWithStreamingResponse + + return AsyncSearchForStopResourceWithStreamingResponse(self._client.search_for_stop) + + @cached_property + def search_for_route(self) -> search_for_route.AsyncSearchForRouteResourceWithStreamingResponse: + from .resources.search_for_route import AsyncSearchForRouteResourceWithStreamingResponse + + return AsyncSearchForRouteResourceWithStreamingResponse(self._client.search_for_route) + + @cached_property + def block(self) -> block.AsyncBlockResourceWithStreamingResponse: + from .resources.block import AsyncBlockResourceWithStreamingResponse + + return AsyncBlockResourceWithStreamingResponse(self._client.block) + + @cached_property + def shape(self) -> shape.AsyncShapeResourceWithStreamingResponse: + from .resources.shape import AsyncShapeResourceWithStreamingResponse + + return AsyncShapeResourceWithStreamingResponse(self._client.shape) Client = OnebusawaySDK From bb271d4d067c06c8848488a5ba050e89b85fd671 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 18 Dec 2025 09:34:09 +0000 Subject: [PATCH 15/18] fix: use async_to_httpx_files in patch method --- src/onebusaway/_base_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/onebusaway/_base_client.py b/src/onebusaway/_base_client.py index 99208e6..1f218e3 100644 --- a/src/onebusaway/_base_client.py +++ b/src/onebusaway/_base_client.py @@ -1774,7 +1774,7 @@ async def patch( options: RequestOptions = {}, ) -> ResponseT: opts = FinalRequestOptions.construct( - method="patch", url=path, json_data=body, files=to_httpx_files(files), **options + method="patch", url=path, json_data=body, files=await async_to_httpx_files(files), **options ) return await self.request(cast_to, opts) From fecb3edeae22300f16eacd4f35da31e2243f17c8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 19 Dec 2025 08:05:37 +0000 Subject: [PATCH 16/18] chore(internal): add `--fix` argument to lint script --- scripts/lint | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/lint b/scripts/lint index 67032eb..ed21d54 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,8 +4,13 @@ set -e cd "$(dirname "$0")/.." -echo "==> Running lints" -rye run lint +if [ "$1" = "--fix" ]; then + echo "==> Running lints with --fix" + rye run fix:ruff +else + echo "==> Running lints" + rye run lint +fi echo "==> Making sure it imports" rye run python -c 'import onebusaway' From dc918e3df35585c12b7a05e433826563faccb086 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 1 Jan 2026 03:01:16 +0000 Subject: [PATCH 17/18] chore(internal): codegen related update --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 443d70c..26680ba 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 Onebusaway SDK + Copyright 2026 Onebusaway SDK Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 38527d7ae133c91f3fdbf542ce7effaac5222180 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 2 Jan 2026 16:10:47 +0000 Subject: [PATCH 18/18] release: 1.17.8 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ pyproject.toml | 2 +- src/onebusaway/_version.py | 2 +- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index fb611b1..87b856c 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "1.17.7" + ".": "1.17.8" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index dee931b..b52307e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # Changelog +## 1.17.8 (2026-01-02) + +Full Changelog: [v1.17.7...v1.17.8](https://github.com/OneBusAway/python-sdk/compare/v1.17.7...v1.17.8) + +### Bug Fixes + +* compat with Python 3.14 ([2ebc518](https://github.com/OneBusAway/python-sdk/commit/2ebc5184554db31387b2f683265720d58dd9bb2f)) +* **compat:** update signatures of `model_dump` and `model_dump_json` for Pydantic v1 ([37abc5b](https://github.com/OneBusAway/python-sdk/commit/37abc5b808843321a5011b935590c5d3455f0c27)) +* ensure streams are always closed ([75f1288](https://github.com/OneBusAway/python-sdk/commit/75f1288ddc3202c2fe6850b8f968720ed88cb470)) +* **types:** allow pyright to infer TypedDict types within SequenceNotStr ([f10f373](https://github.com/OneBusAway/python-sdk/commit/f10f3734af08ea934c7b5be9de0cd2af106afaea)) +* use async_to_httpx_files in patch method ([bb271d4](https://github.com/OneBusAway/python-sdk/commit/bb271d4d067c06c8848488a5ba050e89b85fd671)) + + +### Chores + +* add missing docstrings ([5daefdd](https://github.com/OneBusAway/python-sdk/commit/5daefdde179696d3ade876b33b94fb79f5972155)) +* add Python 3.14 classifier and testing ([5ba9679](https://github.com/OneBusAway/python-sdk/commit/5ba9679c37d905d2b994fb3ad033825142ee19e2)) +* **deps:** mypy 1.18.1 has a regression, pin to 1.17 ([167648d](https://github.com/OneBusAway/python-sdk/commit/167648d8fb485e522aa49611ee25523190b78c9a)) +* **docs:** use environment variables for authentication in code snippets ([a2ac5df](https://github.com/OneBusAway/python-sdk/commit/a2ac5df1da8f164cbe85325385266b5340fd361b)) +* **internal/tests:** avoid race condition with implicit client cleanup ([f6c9ee8](https://github.com/OneBusAway/python-sdk/commit/f6c9ee8b1713fee3b65a599c98653d6183d6e162)) +* **internal:** add `--fix` argument to lint script ([fecb3ed](https://github.com/OneBusAway/python-sdk/commit/fecb3edeae22300f16eacd4f35da31e2243f17c8)) +* **internal:** add missing files argument to base client ([1744224](https://github.com/OneBusAway/python-sdk/commit/17442243ef6d3ca342ac4294de2257e59fdd7da4)) +* **internal:** codegen related update ([dc918e3](https://github.com/OneBusAway/python-sdk/commit/dc918e3df35585c12b7a05e433826563faccb086)) +* **internal:** grammar fix (it's -> its) ([aa8df91](https://github.com/OneBusAway/python-sdk/commit/aa8df91bb2ba826f49bacf3a2a777579931487d9)) +* **package:** drop Python 3.8 support ([b633259](https://github.com/OneBusAway/python-sdk/commit/b633259385cddf32422b425a174a2a7dbe34021c)) +* speedup initial import ([d938f66](https://github.com/OneBusAway/python-sdk/commit/d938f6643cf144bb8db22d8c89024785ff5fdd97)) +* update lockfile ([4fd805d](https://github.com/OneBusAway/python-sdk/commit/4fd805dfa1c4efe2fd53d7aa46c75e368c97463f)) + ## 1.17.7 (2025-10-30) Full Changelog: [v1.17.6...v1.17.7](https://github.com/OneBusAway/python-sdk/compare/v1.17.6...v1.17.7) diff --git a/pyproject.toml b/pyproject.toml index 9f61ec1..f8111ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "onebusaway" -version = "1.17.7" +version = "1.17.8" description = "The official Python library for the onebusaway-sdk API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/onebusaway/_version.py b/src/onebusaway/_version.py index 8f0a4ce..3310d15 100644 --- a/src/onebusaway/_version.py +++ b/src/onebusaway/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "onebusaway" -__version__ = "1.17.7" # x-release-please-version +__version__ = "1.17.8" # x-release-please-version