Skip to content

Commit

Permalink
chore(internal): codegen related update (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
stainless-app[bot] authored and stainless-bot committed Jul 23, 2024
1 parent 2004d59 commit 216fe46
Show file tree
Hide file tree
Showing 19 changed files with 204 additions and 38 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT}

USER vscode

RUN curl -sSf https://rye-up.com/get | RYE_VERSION="0.24.0" RYE_INSTALL_OPTION="--yes" bash
RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.35.0" RYE_INSTALL_OPTION="--yes" bash
ENV PATH=/home/vscode/.rye/shims:$PATH

RUN echo "[[ -d .venv ]] && source .venv/bin/activate" >> /home/vscode/.bashrc
9 changes: 5 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
pull_request:
branches:
- main
- next

jobs:
lint:
Expand All @@ -18,10 +19,10 @@ jobs:

- name: Install Rye
run: |
curl -sSf https://rye-up.com/get | bash
curl -sSf https://rye.astral.sh/get | bash
echo "$HOME/.rye/shims" >> $GITHUB_PATH
env:
RYE_VERSION: 0.24.0
RYE_VERSION: '0.35.0'
RYE_INSTALL_OPTION: '--yes'

- name: Install dependencies
Expand All @@ -38,10 +39,10 @@ jobs:

- name: Install Rye
run: |
curl -sSf https://rye-up.com/get | bash
curl -sSf https://rye.astral.sh/get | bash
echo "$HOME/.rye/shims" >> $GITHUB_PATH
env:
RYE_VERSION: 0.24.0
RYE_VERSION: '0.35.0'
RYE_INSTALL_OPTION: '--yes'

- name: Bootstrap
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ jobs:

- name: Install Rye
run: |
curl -sSf https://rye-up.com/get | bash
curl -sSf https://rye.astral.sh/get | bash
echo "$HOME/.rye/shims" >> $GITHUB_PATH
env:
RYE_VERSION: 0.24.0
RYE_INSTALL_OPTION: "--yes"
RYE_VERSION: '0.35.0'
RYE_INSTALL_OPTION: '--yes'

- name: Publish to PyPI
run: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.prism.log
.vscode
_dev

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

### With Rye

We use [Rye](https://rye-up.com/) to manage dependencies so we highly recommend [installing it](https://rye-up.com/guide/installation/) as it will automatically provision a Python environment with the expected Python version.
We use [Rye](https://rye.astral.sh/) to manage dependencies so we highly recommend [installing it](https://rye.astral.sh/guide/installation/) as it will automatically provision a Python environment with the expected Python version.

After installing Rye, you'll just have to run this command:

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ You can directly override the [httpx client](https://www.python-httpx.org/api/#c

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

```python
from rizaio import Riza, DefaultHttpxClient
Expand Down
3 changes: 3 additions & 0 deletions bin/publish-pypi
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@
set -eux
mkdir -p dist
rye build --clean
# Patching importlib-metadata version until upstream library version is updated
# https://github.com/pypa/twine/issues/977#issuecomment-2189800841
"$HOME/.rye/self/bin/python3" -m pip install 'importlib-metadata==7.2.1'
rye publish --yes --token=$PYPI_TOKEN
16 changes: 16 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ dev-dependencies = [
"nox",
"dirty-equals>=0.6.0",
"importlib-metadata>=6.7.0",
"rich>=13.7.1",

]

Expand Down Expand Up @@ -99,6 +100,21 @@ include = [
[tool.hatch.build.targets.wheel]
packages = ["src/rizaio"]

[tool.hatch.build.targets.sdist]
# Basically everything except hidden files/directories (such as .github, .devcontainers, .python-version, etc)
include = [
"/*.toml",
"/*.json",
"/*.lock",
"/*.md",
"/mypy.ini",
"/noxfile.py",
"bin/*",
"examples/*",
"src/*",
"tests/*",
]

[tool.hatch.metadata.hooks.fancy-pypi-readme]
content-type = "text/markdown"

Expand Down
14 changes: 11 additions & 3 deletions requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
-e file:.
annotated-types==0.6.0
# via pydantic
anyio==4.1.0
anyio==4.4.0
# via httpx
# via rizaio
argcomplete==3.1.2
Expand Down Expand Up @@ -45,7 +45,11 @@ idna==3.4
importlib-metadata==7.0.0
iniconfig==2.0.0
# via pytest
mypy==1.7.1
markdown-it-py==3.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
mypy==1.10.1
mypy-extensions==1.0.0
# via mypy
nodeenv==1.8.0
Expand All @@ -64,7 +68,9 @@ pydantic==2.7.1
# via rizaio
pydantic-core==2.18.2
# via pydantic
pyright==1.1.359
pygments==2.18.0
# via rich
pyright==1.1.364
pytest==7.1.1
# via pytest-asyncio
pytest-asyncio==0.21.1
Expand All @@ -73,6 +79,7 @@ python-dateutil==2.8.2
pytz==2023.3.post1
# via dirty-equals
respx==0.20.2
rich==13.7.1
ruff==0.1.9
setuptools==68.2.2
# via nodeenv
Expand All @@ -87,6 +94,7 @@ tomli==2.0.1
# via mypy
# via pytest
typing-extensions==4.8.0
# via anyio
# via mypy
# via pydantic
# via pydantic-core
Expand Down
3 changes: 2 additions & 1 deletion requirements.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
-e file:.
annotated-types==0.6.0
# via pydantic
anyio==4.1.0
anyio==4.4.0
# via httpx
# via rizaio
certifi==2023.7.22
Expand Down Expand Up @@ -39,6 +39,7 @@ sniffio==1.3.0
# via httpx
# via rizaio
typing-extensions==4.8.0
# via anyio
# via pydantic
# via pydantic-core
# via rizaio
2 changes: 1 addition & 1 deletion scripts/bootstrap
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ echo "==> Installing Python dependencies…"
# experimental uv support makes installations significantly faster
rye config --set-bool behavior.use-uv=true

rye sync
rye sync --all-features
67 changes: 54 additions & 13 deletions src/rizaio/_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@
HttpxSendArgs,
AsyncTransport,
RequestOptions,
HttpxRequestFiles,
ModelBuilderProtocol,
)
from ._utils import is_dict, is_list, is_given, lru_cache, is_mapping
from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping
from ._compat import model_copy, model_dump
from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type
from ._response import (
Expand Down Expand Up @@ -358,6 +359,7 @@ def __init__(
self._custom_query = custom_query or {}
self._strict_response_validation = _strict_response_validation
self._idempotency_header = None
self._platform: Platform | None = None

if max_retries is None: # pyright: ignore[reportUnnecessaryComparison]
raise TypeError(
Expand Down Expand Up @@ -456,8 +458,9 @@ def _build_request(
raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`")

headers = self._build_headers(options)
params = _merge_mappings(self._custom_query, options.params)
params = _merge_mappings(self.default_query, options.params)
content_type = headers.get("Content-Type")
files = options.files

# If the given Content-Type header is multipart/form-data then it
# has to be removed so that httpx can generate the header with
Expand All @@ -471,14 +474,23 @@ def _build_request(
headers.pop("Content-Type")

# As we are now sending multipart/form-data instead of application/json
# we need to tell httpx to use it, https://www.python-httpx.org/advanced/#multipart-file-encoding
# we need to tell httpx to use it, https://www.python-httpx.org/advanced/clients/#multipart-file-encoding
if json_data:
if not is_dict(json_data):
raise TypeError(
f"Expected query input to be a dictionary for multipart requests but got {type(json_data)} instead."
)
kwargs["data"] = self._serialize_multipartform(json_data)

# httpx determines whether or not to send a "multipart/form-data"
# request based on the truthiness of the "files" argument.
# This gets around that issue by generating a dict value that
# evaluates to true.
#
# https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186
if not files:
files = cast(HttpxRequestFiles, ForceMultipartDict())

# TODO: report this error to httpx
return self._client.build_request( # pyright: ignore[reportUnknownMemberType]
headers=headers,
Expand All @@ -491,7 +503,7 @@ def _build_request(
# https://github.com/microsoft/pyright/issues/3526#event-6715453066
params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None,
json=json_data,
files=options.files,
files=files,
**kwargs,
)

Expand Down Expand Up @@ -592,6 +604,12 @@ def default_headers(self) -> dict[str, str | Omit]:
**self._custom_headers,
}

@property
def default_query(self) -> dict[str, object]:
return {
**self._custom_query,
}

def _validate_headers(
self,
headers: Headers, # noqa: ARG002
Expand All @@ -616,7 +634,10 @@ def base_url(self, url: URL | str) -> None:
self._base_url = self._enforce_trailing_slash(url if isinstance(url, URL) else URL(url))

def platform_headers(self) -> Dict[str, str]:
return platform_headers(self._version)
# the actual implementation is in a separate `lru_cache` decorated
# function because adding `lru_cache` to methods will leak memory
# https://github.com/python/cpython/issues/88476
return platform_headers(self._version, platform=self._platform)

def _parse_retry_after_header(self, response_headers: Optional[httpx.Headers] = None) -> float | None:
"""Returns a float of the number of seconds (not milliseconds) to wait after retrying, or None if unspecified.
Expand Down Expand Up @@ -934,6 +955,11 @@ def _request(
stream: bool,
stream_cls: type[_StreamT] | None,
) -> ResponseT | _StreamT:
# create a copy of the options we were given so that if the
# options are mutated later & we then retry, the retries are
# given the original options
input_options = model_copy(options)

cast_to = self._maybe_override_cast_to(cast_to, options)
self._prepare_options(options)

Expand All @@ -958,7 +984,7 @@ def _request(

if retries > 0:
return self._retry_request(
options,
input_options,
cast_to,
retries,
stream=stream,
Expand All @@ -973,7 +999,7 @@ def _request(

if retries > 0:
return self._retry_request(
options,
input_options,
cast_to,
retries,
stream=stream,
Expand Down Expand Up @@ -1001,7 +1027,7 @@ def _request(
if retries > 0 and self._should_retry(err.response):
err.response.close()
return self._retry_request(
options,
input_options,
cast_to,
retries,
err.response.headers,
Expand Down Expand Up @@ -1492,6 +1518,16 @@ async def _request(
stream_cls: type[_AsyncStreamT] | None,
remaining_retries: int | None,
) -> ResponseT | _AsyncStreamT:
if self._platform is None:
# `get_platform` can make blocking IO calls so we
# execute it earlier while we are in an async context
self._platform = await asyncify(get_platform)()

# create a copy of the options we were given so that if the
# options are mutated later & we then retry, the retries are
# given the original options
input_options = model_copy(options)

cast_to = self._maybe_override_cast_to(cast_to, options)
await self._prepare_options(options)

Expand All @@ -1514,7 +1550,7 @@ async def _request(

if retries > 0:
return await self._retry_request(
options,
input_options,
cast_to,
retries,
stream=stream,
Expand All @@ -1529,7 +1565,7 @@ async def _request(

if retries > 0:
return await self._retry_request(
options,
input_options,
cast_to,
retries,
stream=stream,
Expand All @@ -1552,7 +1588,7 @@ async def _request(
if retries > 0 and self._should_retry(err.response):
await err.response.aclose()
return await self._retry_request(
options,
input_options,
cast_to,
retries,
err.response.headers,
Expand Down Expand Up @@ -1848,6 +1884,11 @@ def make_request_options(
return options


class ForceMultipartDict(Dict[str, None]):
def __bool__(self) -> bool:
return True


class OtherPlatform:
def __init__(self, name: str) -> None:
self.name = name
Expand Down Expand Up @@ -1915,11 +1956,11 @@ def get_platform() -> Platform:


@lru_cache(maxsize=None)
def platform_headers(version: str) -> Dict[str, str]:
def platform_headers(version: str, *, platform: Platform | None) -> Dict[str, str]:
return {
"X-Stainless-Lang": "python",
"X-Stainless-Package-Version": version,
"X-Stainless-OS": str(get_platform()),
"X-Stainless-OS": str(platform or get_platform()),
"X-Stainless-Arch": str(get_architecture()),
"X-Stainless-Runtime": get_python_runtime(),
"X-Stainless-Runtime-Version": get_python_version(),
Expand Down
Loading

0 comments on commit 216fe46

Please sign in to comment.