Skip to content

Commit

Permalink
Merge pull request #77 from clear-street/release-please--branches--ma…
Browse files Browse the repository at this point in the history
…in--changes--next

release: 0.1.0-alpha.16
  • Loading branch information
sonicxml authored Dec 19, 2024
2 parents 52790e3 + 475b630 commit 90f3f8a
Show file tree
Hide file tree
Showing 16 changed files with 140 additions and 58 deletions.
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.1.0-alpha.15"
".": "0.1.0-alpha.16"
}
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Changelog

## 0.1.0-alpha.16 (2024-12-18)

Full Changelog: [v0.1.0-alpha.15...v0.1.0-alpha.16](https://github.com/clear-street/studio-sdk-python/compare/v0.1.0-alpha.15...v0.1.0-alpha.16)

### Chores

* **internal:** add support for TypeAliasType ([#80](https://github.com/clear-street/studio-sdk-python/issues/80)) ([174dfac](https://github.com/clear-street/studio-sdk-python/commit/174dfac4c311728e5e80dd60828671248078a8d8))
* **internal:** bump pydantic dependency ([#76](https://github.com/clear-street/studio-sdk-python/issues/76)) ([9f6bfa1](https://github.com/clear-street/studio-sdk-python/commit/9f6bfa14408def30dcc33d4953faf017111b75a8))
* **internal:** bump pyright ([#79](https://github.com/clear-street/studio-sdk-python/issues/79)) ([78f1099](https://github.com/clear-street/studio-sdk-python/commit/78f10998fab7d9789b01e8c68e9c376cef802189))
* **internal:** codegen related update ([#81](https://github.com/clear-street/studio-sdk-python/issues/81)) ([5ebf768](https://github.com/clear-street/studio-sdk-python/commit/5ebf7684b4a459b3c070df3758bab4ce4ae4fac7))
* **internal:** fix some typos ([#83](https://github.com/clear-street/studio-sdk-python/issues/83)) ([2f9c6fa](https://github.com/clear-street/studio-sdk-python/commit/2f9c6faa24900512a7b40c25256fe8dee0d5003b))


### Documentation

* **readme:** example snippet for client context manager ([#82](https://github.com/clear-street/studio-sdk-python/issues/82)) ([6d2b4a7](https://github.com/clear-street/studio-sdk-python/commit/6d2b4a7060ca8d6652ea559760657c58e7be0618))
* **readme:** fix http client proxies example ([#78](https://github.com/clear-street/studio-sdk-python/issues/78)) ([d3e3918](https://github.com/clear-street/studio-sdk-python/commit/d3e3918a7e9e29776a017fc06ee2ed6c762eaec2))

## 0.1.0-alpha.15 (2024-12-09)

Full Changelog: [v0.1.0-alpha.14...v0.1.0-alpha.15](https://github.com/clear-street/studio-sdk-python/compare/v0.1.0-alpha.14...v0.1.0-alpha.15)
Expand Down
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,18 +284,19 @@ can also get all the extra fields on the Pydantic model as a dict with

You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:

- Support for proxies
- Custom transports
- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)
- Custom [transports](https://www.python-httpx.org/advanced/transports/)
- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality

```python
import httpx
from studio_sdk import StudioSDK, DefaultHttpxClient

client = StudioSDK(
# Or use the `STUDIO_SDK_BASE_URL` env var
base_url="http://my.test.server.example.com:8083",
http_client=DefaultHttpxClient(
proxies="http://my.test.proxy.example.com",
proxy="http://my.test.proxy.example.com",
transport=httpx.HTTPTransport(local_address="0.0.0.0"),
),
)
Expand All @@ -311,6 +312,16 @@ client.with_options(http_client=DefaultHttpxClient(...))

By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.

```py
from studio_sdk import StudioSDK

with StudioSDK() as client:
# make requests here
...

# HTTP client is now closed
```

## Versioning

This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "clear-street-studio-sdk"
version = "0.1.0-alpha.15"
version = "0.1.0-alpha.16"
description = "The official Python library for the studio-sdk API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand All @@ -10,7 +10,7 @@ authors = [
dependencies = [
"httpx>=0.23.0, <1",
"pydantic>=1.9.0, <3",
"typing-extensions>=4.7, <5",
"typing-extensions>=4.10, <5",
"anyio>=3.5.0, <5",
"distro>=1.7.0, <2",
"sniffio",
Expand Down
6 changes: 3 additions & 3 deletions requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ platformdirs==3.11.0
# via virtualenv
pluggy==1.5.0
# via pytest
pydantic==2.9.2
pydantic==2.10.3
# via clear-street-studio-sdk
pydantic-core==2.23.4
pydantic-core==2.27.1
# via pydantic
pygments==2.18.0
# via rich
pyright==1.1.389
pyright==1.1.390
pytest==8.3.3
# via pytest-asyncio
pytest-asyncio==0.24.0
Expand Down
4 changes: 2 additions & 2 deletions requirements.lock
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ httpx==0.25.2
idna==3.4
# via anyio
# via httpx
pydantic==2.9.2
pydantic==2.10.3
# via clear-street-studio-sdk
pydantic-core==2.23.4
pydantic-core==2.27.1
# via pydantic
sniffio==1.3.0
# via anyio
Expand Down
54 changes: 28 additions & 26 deletions src/studio_sdk/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import httpx

from . import resources, _exceptions
from . import _exceptions
from ._qs import Querystring
from ._types import (
NOT_GIVEN,
Expand All @@ -24,21 +24,23 @@
get_async_library,
)
from ._version import __version__
from .resources import instruments
from ._streaming import Stream as Stream, AsyncStream as AsyncStream
from ._exceptions import APIStatusError, StudioSDKError
from ._base_client import (
DEFAULT_MAX_RETRIES,
SyncAPIClient,
AsyncAPIClient,
)
from .resources.accounts import accounts
from .resources.entities import entities

__all__ = [
"ENVIRONMENTS",
"Timeout",
"Transport",
"ProxiesTypes",
"RequestOptions",
"resources",
"StudioSDK",
"AsyncStudioSDK",
"Client",
Expand All @@ -52,9 +54,9 @@


class StudioSDK(SyncAPIClient):
entities: resources.EntitiesResource
accounts: resources.AccountsResource
instruments: resources.InstrumentsResource
entities: entities.EntitiesResource
accounts: accounts.AccountsResource
instruments: instruments.InstrumentsResource
with_raw_response: StudioSDKWithRawResponse
with_streaming_response: StudioSDKWithStreamedResponse

Expand Down Expand Up @@ -136,9 +138,9 @@ def __init__(
_strict_response_validation=_strict_response_validation,
)

self.entities = resources.EntitiesResource(self)
self.accounts = resources.AccountsResource(self)
self.instruments = resources.InstrumentsResource(self)
self.entities = entities.EntitiesResource(self)
self.accounts = accounts.AccountsResource(self)
self.instruments = instruments.InstrumentsResource(self)
self.with_raw_response = StudioSDKWithRawResponse(self)
self.with_streaming_response = StudioSDKWithStreamedResponse(self)

Expand Down Expand Up @@ -250,9 +252,9 @@ def _make_status_error(


class AsyncStudioSDK(AsyncAPIClient):
entities: resources.AsyncEntitiesResource
accounts: resources.AsyncAccountsResource
instruments: resources.AsyncInstrumentsResource
entities: entities.AsyncEntitiesResource
accounts: accounts.AsyncAccountsResource
instruments: instruments.AsyncInstrumentsResource
with_raw_response: AsyncStudioSDKWithRawResponse
with_streaming_response: AsyncStudioSDKWithStreamedResponse

Expand Down Expand Up @@ -334,9 +336,9 @@ def __init__(
_strict_response_validation=_strict_response_validation,
)

self.entities = resources.AsyncEntitiesResource(self)
self.accounts = resources.AsyncAccountsResource(self)
self.instruments = resources.AsyncInstrumentsResource(self)
self.entities = entities.AsyncEntitiesResource(self)
self.accounts = accounts.AsyncAccountsResource(self)
self.instruments = instruments.AsyncInstrumentsResource(self)
self.with_raw_response = AsyncStudioSDKWithRawResponse(self)
self.with_streaming_response = AsyncStudioSDKWithStreamedResponse(self)

Expand Down Expand Up @@ -449,30 +451,30 @@ def _make_status_error(

class StudioSDKWithRawResponse:
def __init__(self, client: StudioSDK) -> None:
self.entities = resources.EntitiesResourceWithRawResponse(client.entities)
self.accounts = resources.AccountsResourceWithRawResponse(client.accounts)
self.instruments = resources.InstrumentsResourceWithRawResponse(client.instruments)
self.entities = entities.EntitiesResourceWithRawResponse(client.entities)
self.accounts = accounts.AccountsResourceWithRawResponse(client.accounts)
self.instruments = instruments.InstrumentsResourceWithRawResponse(client.instruments)


class AsyncStudioSDKWithRawResponse:
def __init__(self, client: AsyncStudioSDK) -> None:
self.entities = resources.AsyncEntitiesResourceWithRawResponse(client.entities)
self.accounts = resources.AsyncAccountsResourceWithRawResponse(client.accounts)
self.instruments = resources.AsyncInstrumentsResourceWithRawResponse(client.instruments)
self.entities = entities.AsyncEntitiesResourceWithRawResponse(client.entities)
self.accounts = accounts.AsyncAccountsResourceWithRawResponse(client.accounts)
self.instruments = instruments.AsyncInstrumentsResourceWithRawResponse(client.instruments)


class StudioSDKWithStreamedResponse:
def __init__(self, client: StudioSDK) -> None:
self.entities = resources.EntitiesResourceWithStreamingResponse(client.entities)
self.accounts = resources.AccountsResourceWithStreamingResponse(client.accounts)
self.instruments = resources.InstrumentsResourceWithStreamingResponse(client.instruments)
self.entities = entities.EntitiesResourceWithStreamingResponse(client.entities)
self.accounts = accounts.AccountsResourceWithStreamingResponse(client.accounts)
self.instruments = instruments.InstrumentsResourceWithStreamingResponse(client.instruments)


class AsyncStudioSDKWithStreamedResponse:
def __init__(self, client: AsyncStudioSDK) -> None:
self.entities = resources.AsyncEntitiesResourceWithStreamingResponse(client.entities)
self.accounts = resources.AsyncAccountsResourceWithStreamingResponse(client.accounts)
self.instruments = resources.AsyncInstrumentsResourceWithStreamingResponse(client.instruments)
self.entities = entities.AsyncEntitiesResourceWithStreamingResponse(client.entities)
self.accounts = accounts.AsyncAccountsResourceWithStreamingResponse(client.accounts)
self.instruments = instruments.AsyncInstrumentsResourceWithStreamingResponse(client.instruments)


Client = StudioSDK
Expand Down
3 changes: 3 additions & 0 deletions src/studio_sdk/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
strip_not_given,
extract_type_arg,
is_annotated_type,
is_type_alias_type,
strip_annotated_type,
)
from ._compat import (
Expand Down Expand Up @@ -428,6 +429,8 @@ def construct_type(*, value: object, type_: object) -> object:
# we allow `object` as the input type because otherwise, passing things like
# `Literal['value']` will be reported as a type error by type checkers
type_ = cast("type[object]", type_)
if is_type_alias_type(type_):
type_ = type_.__value__ # type: ignore[unreachable]

# unwrap `Annotated[T, ...]` -> `T`
if is_annotated_type(type_):
Expand Down
20 changes: 10 additions & 10 deletions src/studio_sdk/_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import pydantic

from ._types import NoneType
from ._utils import is_given, extract_type_arg, is_annotated_type, extract_type_var_from_base
from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type, extract_type_var_from_base
from ._models import BaseModel, is_basemodel
from ._constants import RAW_RESPONSE_HEADER, OVERRIDE_CAST_TO_HEADER
from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type
Expand Down Expand Up @@ -126,9 +126,15 @@ def __repr__(self) -> str:
)

def _parse(self, *, to: type[_T] | None = None) -> R | _T:
cast_to = to if to is not None else self._cast_to

# unwrap `TypeAlias('Name', T)` -> `T`
if is_type_alias_type(cast_to):
cast_to = cast_to.__value__ # type: ignore[unreachable]

# unwrap `Annotated[T, ...]` -> `T`
if to and is_annotated_type(to):
to = extract_type_arg(to, 0)
if cast_to and is_annotated_type(cast_to):
cast_to = extract_type_arg(cast_to, 0)

if self._is_sse_stream:
if to:
Expand Down Expand Up @@ -164,18 +170,12 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
return cast(
R,
stream_cls(
cast_to=self._cast_to,
cast_to=cast_to,
response=self.http_response,
client=cast(Any, self._client),
),
)

cast_to = to if to is not None else self._cast_to

# unwrap `Annotated[T, ...]` -> `T`
if is_annotated_type(cast_to):
cast_to = extract_type_arg(cast_to, 0)

if cast_to is NoneType:
return cast(R, None)

Expand Down
6 changes: 2 additions & 4 deletions src/studio_sdk/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,8 @@ def get(self, __key: str) -> str | None: ...
StrBytesIntFloat = Union[str, bytes, int, float]

# Note: copied from Pydantic
# https://github.com/pydantic/pydantic/blob/32ea570bf96e84234d2992e1ddf40ab8a565925a/pydantic/main.py#L49
IncEx: TypeAlias = Union[
Set[int], Set[str], Mapping[int, Union["IncEx", Literal[True]]], Mapping[str, Union["IncEx", Literal[True]]]
]
# https://github.com/pydantic/pydantic/blob/6f31f8f68ef011f84357330186f603ff295312fd/pydantic/main.py#L79
IncEx: TypeAlias = Union[Set[int], Set[str], Mapping[int, Union["IncEx", bool]], Mapping[str, Union["IncEx", bool]]]

PostParser = Callable[[Any], Any]

Expand Down
1 change: 1 addition & 0 deletions src/studio_sdk/_utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
is_iterable_type as is_iterable_type,
is_required_type as is_required_type,
is_annotated_type as is_annotated_type,
is_type_alias_type as is_type_alias_type,
strip_annotated_type as strip_annotated_type,
extract_type_var_from_base as extract_type_var_from_base,
)
Expand Down
31 changes: 30 additions & 1 deletion src/studio_sdk/_utils/_typing.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
from __future__ import annotations

import sys
import typing
import typing_extensions
from typing import Any, TypeVar, Iterable, cast
from collections import abc as _c_abc
from typing_extensions import Required, Annotated, get_args, get_origin
from typing_extensions import (
TypeIs,
Required,
Annotated,
get_args,
get_origin,
)

from .._types import InheritsGeneric
from .._compat import is_union as _is_union
Expand Down Expand Up @@ -36,6 +45,26 @@ def is_typevar(typ: type) -> bool:
return type(typ) == TypeVar # type: ignore


_TYPE_ALIAS_TYPES: tuple[type[typing_extensions.TypeAliasType], ...] = (typing_extensions.TypeAliasType,)
if sys.version_info >= (3, 12):
_TYPE_ALIAS_TYPES = (*_TYPE_ALIAS_TYPES, typing.TypeAliasType)


def is_type_alias_type(tp: Any, /) -> TypeIs[typing_extensions.TypeAliasType]:
"""Return whether the provided argument is an instance of `TypeAliasType`.
```python
type Int = int
is_type_alias_type(Int)
# > True
Str = TypeAliasType("Str", str)
is_type_alias_type(Str)
# > True
```
"""
return isinstance(tp, _TYPE_ALIAS_TYPES)


# Extracts T from Annotated[T, ...] or from Required[Annotated[T, ...]]
def strip_annotated_type(typ: type) -> type:
if is_required_type(typ) or is_annotated_type(typ):
Expand Down
2 changes: 1 addition & 1 deletion src/studio_sdk/_version.py
Original file line number Diff line number Diff line change
@@ -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.15" # x-release-please-version
__version__ = "0.1.0-alpha.16" # x-release-please-version
Loading

0 comments on commit 90f3f8a

Please sign in to comment.