From 8fc74d66d9b93ab77093788b9f29c56fcfff1478 Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 25 Oct 2024 14:36:07 +0000
Subject: [PATCH 1/2] feat(api): enable inventories endpoint (#54)
---
.stats.yml | 2 +-
api.md | 12 ++
pyproject.toml | 8 +-
requirements-dev.lock | 2 +-
src/studio_sdk/_base_client.py | 11 +-
src/studio_sdk/resources/accounts/__init__.py | 14 ++
src/studio_sdk/resources/accounts/accounts.py | 32 ++++
.../resources/accounts/inventories.py | 173 ++++++++++++++++++
src/studio_sdk/types/account.py | 1 -
src/studio_sdk/types/accounts/__init__.py | 1 +
.../accounts/inventory_retrieve_response.py | 23 +++
.../types/accounts/order_create_response.py | 1 -
.../types/accounts/order_retrieve_response.py | 1 -
.../regt_margin_simulation_create_response.py | 1 -
src/studio_sdk/types/pnl_summary.py | 1 -
.../types/shared/regt_margin_simulation.py | 1 -
.../accounts/test_inventories.py | 118 ++++++++++++
tests/test_client.py | 23 ++-
tests/test_models.py | 2 +-
19 files changed, 408 insertions(+), 19 deletions(-)
create mode 100644 src/studio_sdk/resources/accounts/inventories.py
create mode 100644 src/studio_sdk/types/accounts/inventory_retrieve_response.py
create mode 100644 tests/api_resources/accounts/test_inventories.py
diff --git a/.stats.yml b/.stats.yml
index 7c7707f..dc937dc 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,2 @@
-configured_endpoints: 29
+configured_endpoints: 30
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/clear-street%2Fstudio-sdk-468b5da24bbf73b3a3861d44c5a8051fe6c55a6ec64c5c6f2d45f22c76bf35b2.yml
diff --git a/api.md b/api.md
index 4da6f26..c99849f 100644
--- a/api.md
+++ b/api.md
@@ -197,6 +197,18 @@ Methods:
- client.accounts.holdings.list(account_id, \*\*params) -> HoldingListResponse
+## Inventories
+
+Types:
+
+```python
+from studio_sdk.types.accounts import InventoryRetrieveResponse
+```
+
+Methods:
+
+- client.accounts.inventories.retrieve(symbol, \*, account_id) -> InventoryRetrieveResponse
+
# Instruments
Types:
diff --git a/pyproject.toml b/pyproject.toml
index c830484..52662ac 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -63,11 +63,11 @@ format = { chain = [
"format:ruff",
"format:docs",
"fix:ruff",
+ # run formatting again to fix any inconsistencies when imports are stripped
+ "format:ruff",
]}
-"format:black" = "black ."
"format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md"
"format:ruff" = "ruff format"
-"format:isort" = "isort ."
"lint" = { chain = [
"check:ruff",
@@ -125,10 +125,6 @@ path = "README.md"
pattern = '\[(.+?)\]\(((?!https?://)\S+?)\)'
replacement = '[\1](https://github.com/clear-street/studio-sdk-python/tree/main/\g<2>)'
-[tool.black]
-line-length = 120
-target-version = ["py37"]
-
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "--tb=short"
diff --git a/requirements-dev.lock b/requirements-dev.lock
index c976df1..52085ff 100644
--- a/requirements-dev.lock
+++ b/requirements-dev.lock
@@ -80,7 +80,7 @@ pytz==2023.3.post1
# via dirty-equals
respx==0.20.2
rich==13.7.1
-ruff==0.6.5
+ruff==0.6.9
setuptools==68.2.2
# via nodeenv
six==1.16.0
diff --git a/src/studio_sdk/_base_client.py b/src/studio_sdk/_base_client.py
index c659df4..b7a98a0 100644
--- a/src/studio_sdk/_base_client.py
+++ b/src/studio_sdk/_base_client.py
@@ -143,6 +143,12 @@ def __init__(
self.url = url
self.params = params
+ @override
+ def __repr__(self) -> str:
+ if self.url:
+ return f"{self.__class__.__name__}(url={self.url})"
+ return f"{self.__class__.__name__}(params={self.params})"
+
class BasePage(GenericModel, Generic[_T]):
"""
@@ -689,7 +695,8 @@ def _calculate_retry_timeout(
if retry_after is not None and 0 < retry_after <= 60:
return retry_after
- nb_retries = max_retries - remaining_retries
+ # Also cap retry count to 1000 to avoid any potential overflows with `pow`
+ nb_retries = min(max_retries - remaining_retries, 1000)
# Apply exponential backoff, but not more than the max.
sleep_seconds = min(INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY)
@@ -1568,7 +1575,7 @@ async def _request(
except Exception as err:
log.debug("Encountered Exception", exc_info=True)
- if retries_taken > 0:
+ if remaining_retries > 0:
return await self._retry_request(
input_options,
cast_to,
diff --git a/src/studio_sdk/resources/accounts/__init__.py b/src/studio_sdk/resources/accounts/__init__.py
index 99fbacb..03df518 100644
--- a/src/studio_sdk/resources/accounts/__init__.py
+++ b/src/studio_sdk/resources/accounts/__init__.py
@@ -56,6 +56,14 @@
BulkOrdersResourceWithStreamingResponse,
AsyncBulkOrdersResourceWithStreamingResponse,
)
+from .inventories import (
+ InventoriesResource,
+ AsyncInventoriesResource,
+ InventoriesResourceWithRawResponse,
+ AsyncInventoriesResourceWithRawResponse,
+ InventoriesResourceWithStreamingResponse,
+ AsyncInventoriesResourceWithStreamingResponse,
+)
from .pnl_details import (
PnlDetailsResource,
AsyncPnlDetailsResource,
@@ -150,6 +158,12 @@
"AsyncHoldingsResourceWithRawResponse",
"HoldingsResourceWithStreamingResponse",
"AsyncHoldingsResourceWithStreamingResponse",
+ "InventoriesResource",
+ "AsyncInventoriesResource",
+ "InventoriesResourceWithRawResponse",
+ "AsyncInventoriesResourceWithRawResponse",
+ "InventoriesResourceWithStreamingResponse",
+ "AsyncInventoriesResourceWithStreamingResponse",
"AccountsResource",
"AsyncAccountsResource",
"AccountsResourceWithRawResponse",
diff --git a/src/studio_sdk/resources/accounts/accounts.py b/src/studio_sdk/resources/accounts/accounts.py
index a87dd7b..76c4752 100644
--- a/src/studio_sdk/resources/accounts/accounts.py
+++ b/src/studio_sdk/resources/accounts/accounts.py
@@ -61,6 +61,14 @@
BulkOrdersResourceWithStreamingResponse,
AsyncBulkOrdersResourceWithStreamingResponse,
)
+from .inventories import (
+ InventoriesResource,
+ AsyncInventoriesResource,
+ InventoriesResourceWithRawResponse,
+ AsyncInventoriesResourceWithRawResponse,
+ InventoriesResourceWithStreamingResponse,
+ AsyncInventoriesResourceWithStreamingResponse,
+)
from .pnl_details import (
PnlDetailsResource,
AsyncPnlDetailsResource,
@@ -141,6 +149,10 @@ def pnl_sums(self) -> PnlSumsResource:
def holdings(self) -> HoldingsResource:
return HoldingsResource(self._client)
+ @cached_property
+ def inventories(self) -> InventoriesResource:
+ return InventoriesResource(self._client)
+
@cached_property
def with_raw_response(self) -> AccountsResourceWithRawResponse:
"""
@@ -256,6 +268,10 @@ def pnl_sums(self) -> AsyncPnlSumsResource:
def holdings(self) -> AsyncHoldingsResource:
return AsyncHoldingsResource(self._client)
+ @cached_property
+ def inventories(self) -> AsyncInventoriesResource:
+ return AsyncInventoriesResource(self._client)
+
@cached_property
def with_raw_response(self) -> AsyncAccountsResourceWithRawResponse:
"""
@@ -381,6 +397,10 @@ def pnl_sums(self) -> PnlSumsResourceWithRawResponse:
def holdings(self) -> HoldingsResourceWithRawResponse:
return HoldingsResourceWithRawResponse(self._accounts.holdings)
+ @cached_property
+ def inventories(self) -> InventoriesResourceWithRawResponse:
+ return InventoriesResourceWithRawResponse(self._accounts.inventories)
+
class AsyncAccountsResourceWithRawResponse:
def __init__(self, accounts: AsyncAccountsResource) -> None:
@@ -433,6 +453,10 @@ def pnl_sums(self) -> AsyncPnlSumsResourceWithRawResponse:
def holdings(self) -> AsyncHoldingsResourceWithRawResponse:
return AsyncHoldingsResourceWithRawResponse(self._accounts.holdings)
+ @cached_property
+ def inventories(self) -> AsyncInventoriesResourceWithRawResponse:
+ return AsyncInventoriesResourceWithRawResponse(self._accounts.inventories)
+
class AccountsResourceWithStreamingResponse:
def __init__(self, accounts: AccountsResource) -> None:
@@ -485,6 +509,10 @@ def pnl_sums(self) -> PnlSumsResourceWithStreamingResponse:
def holdings(self) -> HoldingsResourceWithStreamingResponse:
return HoldingsResourceWithStreamingResponse(self._accounts.holdings)
+ @cached_property
+ def inventories(self) -> InventoriesResourceWithStreamingResponse:
+ return InventoriesResourceWithStreamingResponse(self._accounts.inventories)
+
class AsyncAccountsResourceWithStreamingResponse:
def __init__(self, accounts: AsyncAccountsResource) -> None:
@@ -536,3 +564,7 @@ def pnl_sums(self) -> AsyncPnlSumsResourceWithStreamingResponse:
@cached_property
def holdings(self) -> AsyncHoldingsResourceWithStreamingResponse:
return AsyncHoldingsResourceWithStreamingResponse(self._accounts.holdings)
+
+ @cached_property
+ def inventories(self) -> AsyncInventoriesResourceWithStreamingResponse:
+ return AsyncInventoriesResourceWithStreamingResponse(self._accounts.inventories)
diff --git a/src/studio_sdk/resources/accounts/inventories.py b/src/studio_sdk/resources/accounts/inventories.py
new file mode 100644
index 0000000..304c841
--- /dev/null
+++ b/src/studio_sdk/resources/accounts/inventories.py
@@ -0,0 +1,173 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ..._base_client import make_request_options
+from ...types.accounts.inventory_retrieve_response import InventoryRetrieveResponse
+
+__all__ = ["InventoriesResource", "AsyncInventoriesResource"]
+
+
+class InventoriesResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> InventoriesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return the
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/clear-street/studio-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return InventoriesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> InventoriesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/clear-street/studio-sdk-python#with_streaming_response
+ """
+ return InventoriesResourceWithStreamingResponse(self)
+
+ def retrieve(
+ self,
+ symbol: str,
+ *,
+ account_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> InventoryRetrieveResponse:
+ """
+ Get located inventory for a symbol.
+
+ Args:
+ account_id: Account ID for the account.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not account_id:
+ raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}")
+ if not symbol:
+ raise ValueError(f"Expected a non-empty value for `symbol` but received {symbol!r}")
+ return self._get(
+ f"/accounts/{account_id}/inventories/{symbol}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InventoryRetrieveResponse,
+ )
+
+
+class AsyncInventoriesResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncInventoriesResourceWithRawResponse:
+ """
+ This property can be used as a prefix for any HTTP method call to return the
+ the raw response object instead of the parsed content.
+
+ For more information, see https://www.github.com/clear-street/studio-sdk-python#accessing-raw-response-data-eg-headers
+ """
+ return AsyncInventoriesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncInventoriesResourceWithStreamingResponse:
+ """
+ An alternative to `.with_raw_response` that doesn't eagerly read the response body.
+
+ For more information, see https://www.github.com/clear-street/studio-sdk-python#with_streaming_response
+ """
+ return AsyncInventoriesResourceWithStreamingResponse(self)
+
+ async def retrieve(
+ self,
+ symbol: str,
+ *,
+ account_id: str,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
+ ) -> InventoryRetrieveResponse:
+ """
+ Get located inventory for a symbol.
+
+ Args:
+ account_id: Account ID for the account.
+
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ if not account_id:
+ raise ValueError(f"Expected a non-empty value for `account_id` but received {account_id!r}")
+ if not symbol:
+ raise ValueError(f"Expected a non-empty value for `symbol` but received {symbol!r}")
+ return await self._get(
+ f"/accounts/{account_id}/inventories/{symbol}",
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=InventoryRetrieveResponse,
+ )
+
+
+class InventoriesResourceWithRawResponse:
+ def __init__(self, inventories: InventoriesResource) -> None:
+ self._inventories = inventories
+
+ self.retrieve = to_raw_response_wrapper(
+ inventories.retrieve,
+ )
+
+
+class AsyncInventoriesResourceWithRawResponse:
+ def __init__(self, inventories: AsyncInventoriesResource) -> None:
+ self._inventories = inventories
+
+ self.retrieve = async_to_raw_response_wrapper(
+ inventories.retrieve,
+ )
+
+
+class InventoriesResourceWithStreamingResponse:
+ def __init__(self, inventories: InventoriesResource) -> None:
+ self._inventories = inventories
+
+ self.retrieve = to_streamed_response_wrapper(
+ inventories.retrieve,
+ )
+
+
+class AsyncInventoriesResourceWithStreamingResponse:
+ def __init__(self, inventories: AsyncInventoriesResource) -> None:
+ self._inventories = inventories
+
+ self.retrieve = async_to_streamed_response_wrapper(
+ inventories.retrieve,
+ )
diff --git a/src/studio_sdk/types/account.py b/src/studio_sdk/types/account.py
index ecce903..a08883e 100644
--- a/src/studio_sdk/types/account.py
+++ b/src/studio_sdk/types/account.py
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
from .._models import BaseModel
__all__ = ["Account"]
diff --git a/src/studio_sdk/types/accounts/__init__.py b/src/studio_sdk/types/accounts/__init__.py
index 707f897..20cbd16 100644
--- a/src/studio_sdk/types/accounts/__init__.py
+++ b/src/studio_sdk/types/accounts/__init__.py
@@ -24,3 +24,4 @@
from .locate_order_create_params import LocateOrderCreateParams as LocateOrderCreateParams
from .locate_order_list_response import LocateOrderListResponse as LocateOrderListResponse
from .locate_order_update_params import LocateOrderUpdateParams as LocateOrderUpdateParams
+from .inventory_retrieve_response import InventoryRetrieveResponse as InventoryRetrieveResponse
diff --git a/src/studio_sdk/types/accounts/inventory_retrieve_response.py b/src/studio_sdk/types/accounts/inventory_retrieve_response.py
new file mode 100644
index 0000000..7b9d796
--- /dev/null
+++ b/src/studio_sdk/types/accounts/inventory_retrieve_response.py
@@ -0,0 +1,23 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from ..._models import BaseModel
+
+__all__ = ["InventoryRetrieveResponse"]
+
+
+class InventoryRetrieveResponse(BaseModel):
+ account_id: Optional[str] = None
+ """Account ID for the account."""
+
+ available: Optional[str] = None
+ """String representation of quantity."""
+
+ reserved: Optional[str] = None
+ """String representation of quantity."""
+
+ symbol: Optional[str] = None
+
+ used: Optional[str] = None
+ """String representation of quantity."""
diff --git a/src/studio_sdk/types/accounts/order_create_response.py b/src/studio_sdk/types/accounts/order_create_response.py
index 8c8c5c2..2b69c87 100644
--- a/src/studio_sdk/types/accounts/order_create_response.py
+++ b/src/studio_sdk/types/accounts/order_create_response.py
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
from ..._models import BaseModel
__all__ = ["OrderCreateResponse"]
diff --git a/src/studio_sdk/types/accounts/order_retrieve_response.py b/src/studio_sdk/types/accounts/order_retrieve_response.py
index c071338..9a763ad 100644
--- a/src/studio_sdk/types/accounts/order_retrieve_response.py
+++ b/src/studio_sdk/types/accounts/order_retrieve_response.py
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
from ..._models import BaseModel
from ..shared.order import Order
diff --git a/src/studio_sdk/types/entities/regt_margin_simulation_create_response.py b/src/studio_sdk/types/entities/regt_margin_simulation_create_response.py
index 464ee59..a765ba0 100644
--- a/src/studio_sdk/types/entities/regt_margin_simulation_create_response.py
+++ b/src/studio_sdk/types/entities/regt_margin_simulation_create_response.py
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
from ..._models import BaseModel
from .simulation_id import SimulationID
diff --git a/src/studio_sdk/types/pnl_summary.py b/src/studio_sdk/types/pnl_summary.py
index 92268c0..c23c973 100644
--- a/src/studio_sdk/types/pnl_summary.py
+++ b/src/studio_sdk/types/pnl_summary.py
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
from .._models import BaseModel
__all__ = ["PnlSummary"]
diff --git a/src/studio_sdk/types/shared/regt_margin_simulation.py b/src/studio_sdk/types/shared/regt_margin_simulation.py
index fd872bb..c84803f 100644
--- a/src/studio_sdk/types/shared/regt_margin_simulation.py
+++ b/src/studio_sdk/types/shared/regt_margin_simulation.py
@@ -1,7 +1,6 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
from ..._models import BaseModel
from ..regt_margin import RegtMargin
from ..entities.simulation_id import SimulationID
diff --git a/tests/api_resources/accounts/test_inventories.py b/tests/api_resources/accounts/test_inventories.py
new file mode 100644
index 0000000..2997240
--- /dev/null
+++ b/tests/api_resources/accounts/test_inventories.py
@@ -0,0 +1,118 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import os
+from typing import Any, cast
+
+import pytest
+
+from studio_sdk import StudioSDK, AsyncStudioSDK
+from tests.utils import assert_matches_type
+from studio_sdk.types.accounts import InventoryRetrieveResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestInventories:
+ parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ def test_method_retrieve(self, client: StudioSDK) -> None:
+ inventory = client.accounts.inventories.retrieve(
+ symbol="AAPL",
+ account_id="x",
+ )
+ assert_matches_type(InventoryRetrieveResponse, inventory, path=["response"])
+
+ @parametrize
+ def test_raw_response_retrieve(self, client: StudioSDK) -> None:
+ response = client.accounts.inventories.with_raw_response.retrieve(
+ symbol="AAPL",
+ account_id="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ inventory = response.parse()
+ assert_matches_type(InventoryRetrieveResponse, inventory, path=["response"])
+
+ @parametrize
+ def test_streaming_response_retrieve(self, client: StudioSDK) -> None:
+ with client.accounts.inventories.with_streaming_response.retrieve(
+ symbol="AAPL",
+ account_id="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ inventory = response.parse()
+ assert_matches_type(InventoryRetrieveResponse, inventory, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ def test_path_params_retrieve(self, client: StudioSDK) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"):
+ client.accounts.inventories.with_raw_response.retrieve(
+ symbol="AAPL",
+ account_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `symbol` but received ''"):
+ client.accounts.inventories.with_raw_response.retrieve(
+ symbol="",
+ account_id="x",
+ )
+
+
+class TestAsyncInventories:
+ parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
+
+ @parametrize
+ async def test_method_retrieve(self, async_client: AsyncStudioSDK) -> None:
+ inventory = await async_client.accounts.inventories.retrieve(
+ symbol="AAPL",
+ account_id="x",
+ )
+ assert_matches_type(InventoryRetrieveResponse, inventory, path=["response"])
+
+ @parametrize
+ async def test_raw_response_retrieve(self, async_client: AsyncStudioSDK) -> None:
+ response = await async_client.accounts.inventories.with_raw_response.retrieve(
+ symbol="AAPL",
+ account_id="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ inventory = await response.parse()
+ assert_matches_type(InventoryRetrieveResponse, inventory, path=["response"])
+
+ @parametrize
+ async def test_streaming_response_retrieve(self, async_client: AsyncStudioSDK) -> None:
+ async with async_client.accounts.inventories.with_streaming_response.retrieve(
+ symbol="AAPL",
+ account_id="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ inventory = await response.parse()
+ assert_matches_type(InventoryRetrieveResponse, inventory, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @parametrize
+ async def test_path_params_retrieve(self, async_client: AsyncStudioSDK) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `account_id` but received ''"):
+ await async_client.accounts.inventories.with_raw_response.retrieve(
+ symbol="AAPL",
+ account_id="",
+ )
+
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `symbol` but received ''"):
+ await async_client.accounts.inventories.with_raw_response.retrieve(
+ symbol="",
+ account_id="x",
+ )
diff --git a/tests/test_client.py b/tests/test_client.py
index 49ec2f6..ac074b5 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -10,6 +10,7 @@
import tracemalloc
from typing import Any, Union, cast
from unittest import mock
+from typing_extensions import Literal
import httpx
import pytest
@@ -730,6 +731,7 @@ class Model(BaseModel):
[3, "", 0.5],
[2, "", 0.5 * 2.0],
[1, "", 0.5 * 4.0],
+ [-1100, "", 7.8], # test large number potentially overflowing
],
)
@mock.patch("time.time", mock.MagicMock(return_value=1696004797))
@@ -764,7 +766,14 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> Non
@pytest.mark.parametrize("failures_before_success", [0, 2, 4])
@mock.patch("studio_sdk._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout)
@pytest.mark.respx(base_url=base_url)
- def test_retries_taken(self, client: StudioSDK, failures_before_success: int, respx_mock: MockRouter) -> None:
+ @pytest.mark.parametrize("failure_mode", ["status", "exception"])
+ def test_retries_taken(
+ self,
+ client: StudioSDK,
+ failures_before_success: int,
+ failure_mode: Literal["status", "exception"],
+ respx_mock: MockRouter,
+ ) -> None:
client = client.with_options(max_retries=4)
nb_retries = 0
@@ -773,6 +782,8 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
nonlocal nb_retries
if nb_retries < failures_before_success:
nb_retries += 1
+ if failure_mode == "exception":
+ raise RuntimeError("oops")
return httpx.Response(500)
return httpx.Response(200)
@@ -1513,6 +1524,7 @@ class Model(BaseModel):
[3, "", 0.5],
[2, "", 0.5 * 2.0],
[1, "", 0.5 * 4.0],
+ [-1100, "", 7.8], # test large number potentially overflowing
],
)
@mock.patch("time.time", mock.MagicMock(return_value=1696004797))
@@ -1553,8 +1565,13 @@ async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter)
@mock.patch("studio_sdk._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, async_client: AsyncStudioSDK, failures_before_success: int, respx_mock: MockRouter
+ self,
+ async_client: AsyncStudioSDK,
+ failures_before_success: int,
+ failure_mode: Literal["status", "exception"],
+ respx_mock: MockRouter,
) -> None:
client = async_client.with_options(max_retries=4)
@@ -1564,6 +1581,8 @@ def retry_handler(_request: httpx.Request) -> httpx.Response:
nonlocal nb_retries
if nb_retries < failures_before_success:
nb_retries += 1
+ if failure_mode == "exception":
+ raise RuntimeError("oops")
return httpx.Response(500)
return httpx.Response(200)
diff --git a/tests/test_models.py b/tests/test_models.py
index c85ecf6..29cda90 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -245,7 +245,7 @@ class Model(BaseModel):
assert m.foo is True
m = Model.construct(foo="CARD_HOLDER")
- assert m.foo is "CARD_HOLDER"
+ assert m.foo == "CARD_HOLDER"
m = Model.construct(foo={"bar": False})
assert isinstance(m.foo, Submodel1)
From b43ca2b8c671173d6e0cdd87174e36aaed6a58ad Mon Sep 17 00:00:00 2001
From: "stainless-app[bot]"
<142633134+stainless-app[bot]@users.noreply.github.com>
Date: Fri, 25 Oct 2024 14:36:24 +0000
Subject: [PATCH 2/2] release: 0.1.0-alpha.12
---
.release-please-manifest.json | 2 +-
CHANGELOG.md | 8 ++++++++
pyproject.toml | 2 +-
src/studio_sdk/_version.py | 2 +-
4 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index ee49ac2..fd0ccba 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.1.0-alpha.11"
+ ".": "0.1.0-alpha.12"
}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f54c2b4..5979d8a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## 0.1.0-alpha.12 (2024-10-25)
+
+Full Changelog: [v0.1.0-alpha.11...v0.1.0-alpha.12](https://github.com/clear-street/studio-sdk-python/compare/v0.1.0-alpha.11...v0.1.0-alpha.12)
+
+### Features
+
+* **api:** enable inventories endpoint ([#54](https://github.com/clear-street/studio-sdk-python/issues/54)) ([8fc74d6](https://github.com/clear-street/studio-sdk-python/commit/8fc74d66d9b93ab77093788b9f29c56fcfff1478))
+
## 0.1.0-alpha.11 (2024-10-11)
Full Changelog: [v0.1.0-alpha.10...v0.1.0-alpha.11](https://github.com/clear-street/studio-sdk-python/compare/v0.1.0-alpha.10...v0.1.0-alpha.11)
diff --git a/pyproject.toml b/pyproject.toml
index 52662ac..4c31df4 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "clear-street-studio-sdk"
-version = "0.1.0-alpha.11"
+version = "0.1.0-alpha.12"
description = "The official Python library for the studio-sdk API"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/src/studio_sdk/_version.py b/src/studio_sdk/_version.py
index 275d8ae..f2c5199 100644
--- a/src/studio_sdk/_version.py
+++ b/src/studio_sdk/_version.py
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
__title__ = "studio_sdk"
-__version__ = "0.1.0-alpha.11" # x-release-please-version
+__version__ = "0.1.0-alpha.12" # x-release-please-version