Skip to content

Commit a26e06f

Browse files
authored
feat: v0.1.2 api update (#34)
* Sync updates from stainless branch: main * 0.1.2
1 parent edca86e commit a26e06f

File tree

14 files changed

+307
-106
lines changed

14 files changed

+307
-106
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ $ rye sync --all-features
1717
You can then run scripts using `rye run python script.py` or by activating the virtual environment:
1818

1919
```sh
20-
$ rye shell
21-
# or manually activate - https://docs.python.org/3/library/venv.html#how-venvs-work
20+
# Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work
2221
$ source .venv/bin/activate
2322

2423
# now you can omit the `rye run` prefix

pyproject.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "llama_api_client"
3-
version = "0.1.1"
3+
version = "0.1.2"
44
description = "The official Python library for the llama-api-client API"
55
dynamic = ["readme"]
66
license = "MIT"
@@ -37,6 +37,8 @@ classifiers = [
3737
Homepage = "https://github.com/meta-llama/llama-api-python"
3838
Repository = "https://github.com/meta-llama/llama-api-python"
3939

40+
[project.optional-dependencies]
41+
aiohttp = ["aiohttp", "httpx_aiohttp>=0.1.6"]
4042

4143
[tool.rye]
4244
managed = true
@@ -54,6 +56,7 @@ dev-dependencies = [
5456
"importlib-metadata>=6.7.0",
5557
"rich>=13.7.1",
5658
"nest_asyncio==1.6.0",
59+
"pytest-xdist>=3.6.1",
5760
]
5861

5962
[tool.rye.scripts]
@@ -125,7 +128,7 @@ replacement = '[\1](https://github.com/meta-llama/llama-api-python/tree/main/\g<
125128

126129
[tool.pytest.ini_options]
127130
testpaths = ["tests"]
128-
addopts = "--tb=short"
131+
addopts = "--tb=short -n auto"
129132
xfail_strict = true
130133
asyncio_mode = "auto"
131134
asyncio_default_fixture_loop_scope = "session"

requirements-dev.lock

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,24 @@
1010
# universal: false
1111

1212
-e file:.
13+
aiohappyeyeballs==2.6.1
14+
# via aiohttp
15+
aiohttp==3.12.8
16+
# via httpx-aiohttp
17+
# via llama-api-client
18+
aiosignal==1.3.2
19+
# via aiohttp
1320
annotated-types==0.6.0
1421
# via pydantic
1522
anyio==4.4.0
1623
# via httpx
1724
# via llama-api-client
1825
argcomplete==3.1.2
1926
# via nox
27+
async-timeout==5.0.1
28+
# via aiohttp
29+
attrs==25.3.0
30+
# via aiohttp
2031
certifi==2023.7.22
2132
# via httpcore
2233
# via httpx
@@ -30,25 +41,37 @@ distro==1.8.0
3041
exceptiongroup==1.2.2
3142
# via anyio
3243
# via pytest
44+
execnet==2.1.1
45+
# via pytest-xdist
3346
filelock==3.12.4
3447
# via virtualenv
48+
frozenlist==1.6.2
49+
# via aiohttp
50+
# via aiosignal
3551
h11==0.14.0
3652
# via httpcore
3753
httpcore==1.0.2
3854
# via httpx
3955
httpx==0.28.1
56+
# via httpx-aiohttp
4057
# via llama-api-client
4158
# via respx
59+
httpx-aiohttp==0.1.6
60+
# via llama-api-client
4261
idna==3.4
4362
# via anyio
4463
# via httpx
64+
# via yarl
4565
importlib-metadata==7.0.0
4666
iniconfig==2.0.0
4767
# via pytest
4868
markdown-it-py==3.0.0
4969
# via rich
5070
mdurl==0.1.2
5171
# via markdown-it-py
72+
multidict==6.4.4
73+
# via aiohttp
74+
# via yarl
5275
mypy==1.14.1
5376
mypy-extensions==1.0.0
5477
# via mypy
@@ -63,6 +86,9 @@ platformdirs==3.11.0
6386
# via virtualenv
6487
pluggy==1.5.0
6588
# via pytest
89+
propcache==0.3.1
90+
# via aiohttp
91+
# via yarl
6692
pydantic==2.10.3
6793
# via llama-api-client
6894
pydantic-core==2.27.1
@@ -72,7 +98,9 @@ pygments==2.18.0
7298
pyright==1.1.399
7399
pytest==8.3.3
74100
# via pytest-asyncio
101+
# via pytest-xdist
75102
pytest-asyncio==0.24.0
103+
pytest-xdist==3.7.0
76104
python-dateutil==2.8.2
77105
# via time-machine
78106
pytz==2023.3.post1
@@ -94,11 +122,14 @@ tomli==2.0.2
94122
typing-extensions==4.12.2
95123
# via anyio
96124
# via llama-api-client
125+
# via multidict
97126
# via mypy
98127
# via pydantic
99128
# via pydantic-core
100129
# via pyright
101130
virtualenv==20.24.5
102131
# via nox
132+
yarl==1.20.0
133+
# via aiohttp
103134
zipp==3.17.0
104135
# via importlib-metadata

requirements.lock

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,51 @@
1010
# universal: false
1111

1212
-e file:.
13+
aiohappyeyeballs==2.6.1
14+
# via aiohttp
15+
aiohttp==3.12.8
16+
# via httpx-aiohttp
17+
# via llama-api-client
18+
aiosignal==1.3.2
19+
# via aiohttp
1320
annotated-types==0.6.0
1421
# via pydantic
1522
anyio==4.4.0
1623
# via httpx
1724
# via llama-api-client
25+
async-timeout==5.0.1
26+
# via aiohttp
27+
attrs==25.3.0
28+
# via aiohttp
1829
certifi==2023.7.22
1930
# via httpcore
2031
# via httpx
2132
distro==1.8.0
2233
# via llama-api-client
2334
exceptiongroup==1.2.2
2435
# via anyio
36+
frozenlist==1.6.2
37+
# via aiohttp
38+
# via aiosignal
2539
h11==0.14.0
2640
# via httpcore
2741
httpcore==1.0.2
2842
# via httpx
2943
httpx==0.28.1
44+
# via httpx-aiohttp
45+
# via llama-api-client
46+
httpx-aiohttp==0.1.6
3047
# via llama-api-client
3148
idna==3.4
3249
# via anyio
3350
# via httpx
51+
# via yarl
52+
multidict==6.4.4
53+
# via aiohttp
54+
# via yarl
55+
propcache==0.3.1
56+
# via aiohttp
57+
# via yarl
3458
pydantic==2.10.3
3559
# via llama-api-client
3660
pydantic-core==2.27.1
@@ -41,5 +65,8 @@ sniffio==1.3.0
4165
typing-extensions==4.12.2
4266
# via anyio
4367
# via llama-api-client
68+
# via multidict
4469
# via pydantic
4570
# via pydantic-core
71+
yarl==1.20.0
72+
# via aiohttp

src/llama_api_client/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
UnprocessableEntityError,
3737
APIResponseValidationError,
3838
)
39-
from ._base_client import DefaultHttpxClient, DefaultAsyncHttpxClient
39+
from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient
4040
from ._utils._logs import setup_logging as _setup_logging
4141

4242
__all__ = [
@@ -78,6 +78,7 @@
7878
"DEFAULT_CONNECTION_LIMITS",
7979
"DefaultHttpxClient",
8080
"DefaultAsyncHttpxClient",
81+
"DefaultAioHttpClient",
8182
]
8283

8384
if not _t.TYPE_CHECKING:

src/llama_api_client/_base_client.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,9 @@ def request(
960960
if self.custom_auth is not None:
961961
kwargs["auth"] = self.custom_auth
962962

963+
if options.follow_redirects is not None:
964+
kwargs["follow_redirects"] = options.follow_redirects
965+
963966
log.debug("Sending HTTP Request: %s %s", request.method, request.url)
964967

965968
response = None
@@ -1068,7 +1071,14 @@ def _process_response(
10681071
) -> ResponseT:
10691072
origin = get_origin(cast_to) or cast_to
10701073

1071-
if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
1074+
if (
1075+
inspect.isclass(origin)
1076+
and issubclass(origin, BaseAPIResponse)
1077+
# we only want to actually return the custom BaseAPIResponse class if we're
1078+
# returning the raw response, or if we're not streaming SSE, as if we're streaming
1079+
# SSE then `cast_to` doesn't actively reflect the type we need to parse into
1080+
and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
1081+
):
10721082
if not issubclass(origin, APIResponse):
10731083
raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}")
10741084

@@ -1279,6 +1289,24 @@ def __init__(self, **kwargs: Any) -> None:
12791289
super().__init__(**kwargs)
12801290

12811291

1292+
try:
1293+
import httpx_aiohttp
1294+
except ImportError:
1295+
1296+
class _DefaultAioHttpClient(httpx.AsyncClient):
1297+
def __init__(self, **_kwargs: Any) -> None:
1298+
raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra")
1299+
else:
1300+
1301+
class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore
1302+
def __init__(self, **kwargs: Any) -> None:
1303+
kwargs.setdefault("timeout", DEFAULT_TIMEOUT)
1304+
kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS)
1305+
kwargs.setdefault("follow_redirects", True)
1306+
1307+
super().__init__(**kwargs)
1308+
1309+
12821310
if TYPE_CHECKING:
12831311
DefaultAsyncHttpxClient = httpx.AsyncClient
12841312
"""An alias to `httpx.AsyncClient` that provides the same defaults that this SDK
@@ -1287,8 +1315,12 @@ def __init__(self, **kwargs: Any) -> None:
12871315
This is useful because overriding the `http_client` with your own instance of
12881316
`httpx.AsyncClient` will result in httpx's defaults being used, not ours.
12891317
"""
1318+
1319+
DefaultAioHttpClient = httpx.AsyncClient
1320+
"""An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`."""
12901321
else:
12911322
DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient
1323+
DefaultAioHttpClient = _DefaultAioHttpClient
12921324

12931325

12941326
class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient):
@@ -1460,6 +1492,9 @@ async def request(
14601492
if self.custom_auth is not None:
14611493
kwargs["auth"] = self.custom_auth
14621494

1495+
if options.follow_redirects is not None:
1496+
kwargs["follow_redirects"] = options.follow_redirects
1497+
14631498
log.debug("Sending HTTP Request: %s %s", request.method, request.url)
14641499

14651500
response = None
@@ -1568,7 +1603,14 @@ async def _process_response(
15681603
) -> ResponseT:
15691604
origin = get_origin(cast_to) or cast_to
15701605

1571-
if inspect.isclass(origin) and issubclass(origin, BaseAPIResponse):
1606+
if (
1607+
inspect.isclass(origin)
1608+
and issubclass(origin, BaseAPIResponse)
1609+
# we only want to actually return the custom BaseAPIResponse class if we're
1610+
# returning the raw response, or if we're not streaming SSE, as if we're streaming
1611+
# SSE then `cast_to` doesn't actively reflect the type we need to parse into
1612+
and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER)))
1613+
):
15721614
if not issubclass(origin, AsyncAPIResponse):
15731615
raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}")
15741616

src/llama_api_client/_models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,7 @@ class FinalRequestOptionsInput(TypedDict, total=False):
737737
idempotency_key: str
738738
json_data: Body
739739
extra_json: AnyMapping
740+
follow_redirects: bool
740741

741742

742743
@final
@@ -750,6 +751,7 @@ class FinalRequestOptions(pydantic.BaseModel):
750751
files: Union[HttpxRequestFiles, None] = None
751752
idempotency_key: Union[str, None] = None
752753
post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven()
754+
follow_redirects: Union[bool, None] = None
753755

754756
# It should be noted that we cannot use `json` here as that would override
755757
# a BaseModel method in an incompatible fashion.

src/llama_api_client/_types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class RequestOptions(TypedDict, total=False):
100100
params: Query
101101
extra_json: AnyMapping
102102
idempotency_key: str
103+
follow_redirects: bool
103104

104105

105106
# Sentinel class used until PEP 0661 is accepted
@@ -215,3 +216,4 @@ class _GenericAlias(Protocol):
215216

216217
class HttpxSendArgs(TypedDict, total=False):
217218
auth: httpx.Auth
219+
follow_redirects: bool

src/llama_api_client/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

33
__title__ = "llama_api_client"
4-
__version__ = "0.1.1"
4+
__version__ = "0.1.2"

tests/api_resources/chat/test_completions.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,9 @@ def test_streaming_response_create_overload_2(self, client: LlamaAPIClient) -> N
205205

206206

207207
class TestAsyncCompletions:
208-
parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"])
208+
parametrize = pytest.mark.parametrize(
209+
"async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"]
210+
)
209211

210212
@pytest.mark.skip()
211213
@parametrize

0 commit comments

Comments
 (0)