diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ba6b37d..97f05b2a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,14 +61,18 @@ jobs: run: rye build - name: Get GitHub OIDC Token - if: github.repository == 'stainless-sdks/steel-python' + if: |- + github.repository == 'stainless-sdks/steel-python' && + !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc uses: actions/github-script@v8 with: script: core.setOutput('github_token', await core.getIDToken()); - name: Upload tarball - if: github.repository == 'stainless-sdks/steel-python' + if: |- + github.repository == 'stainless-sdks/steel-python' && + !startsWith(github.ref, 'refs/heads/stl/') env: URL: https://pkg.stainless.com/s AUTH: ${{ steps.github-oidc.outputs.github_token }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b4e9013b..6db19b95 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.16.0" + ".": "0.17.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 416f1d7a..35acfccf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 39 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/nen-labs%2Fsteel-45efcdf3e5ccffb6e94a86be505b24b7b4ff05d8f1a2978c2a281729af68cb82.yml -openapi_spec_hash: 9a7724672b05d44888d67b6ed0ffc7ca +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/nen-labs%2Fsteel-f51ce05f6128dcdd6b500492869910d3a43737c66d0bc13c3f2e67f42362605c.yml +openapi_spec_hash: c573fb6f26d5fb14eaf92e0a107323ec config_hash: dce4dea59023b0a00890fa654fbfffb4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f1805a8..ab379643 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 0.17.0 (2026-03-16) + +Full Changelog: [v0.16.0...v0.17.0](https://github.com/steel-dev/steel-python/compare/v0.16.0...v0.17.0) + +### Features + +* **api:** api update ([b341bdb](https://github.com/steel-dev/steel-python/commit/b341bdb0c251b50c85d862b77bb23df08562186b)) +* **api:** api update ([bfcb31e](https://github.com/steel-dev/steel-python/commit/bfcb31ebdff79c4115bc2bb6c4f7e0c48a55f469)) +* **api:** api update ([20160d0](https://github.com/steel-dev/steel-python/commit/20160d01b7660dc2b3856a2069d3fe3bde7ad2c0)) + + +### Chores + +* **ci:** skip uploading artifacts on stainless-internal branches ([54e6339](https://github.com/steel-dev/steel-python/commit/54e6339015586e3ffe196c459385cbc2dd6eb94a)) +* format all `api.md` files ([99ec714](https://github.com/steel-dev/steel-python/commit/99ec714917e3375108409099c28ce0a8efc2171e)) +* **internal:** add request options to SSE classes ([5e72d8e](https://github.com/steel-dev/steel-python/commit/5e72d8e76a7e017a7611d87d3b49a1d7e25cd21e)) +* **internal:** bump dependencies ([d04a927](https://github.com/steel-dev/steel-python/commit/d04a92742a449ee597cc68b2312e90a835f9e8b2)) +* **internal:** fix lint error on Python 3.14 ([5bfdbc9](https://github.com/steel-dev/steel-python/commit/5bfdbc994392efd19eb97b366113416dddb4eb69)) +* **internal:** make `test_proxy_environment_variables` more resilient ([2e233ea](https://github.com/steel-dev/steel-python/commit/2e233ea37507adb2f05b4419ef0e8fd1932f6ba4)) +* **internal:** make `test_proxy_environment_variables` more resilient to env ([8b312f4](https://github.com/steel-dev/steel-python/commit/8b312f41858a4abf129a5e5da1ed75d5cddffe16)) +* **test:** do not count install time for mock server timeout ([faf3551](https://github.com/steel-dev/steel-python/commit/faf3551f91a527bada3b902550742dca0668d91f)) +* update mock server docs ([98b44de](https://github.com/steel-dev/steel-python/commit/98b44de2a1a0eb2f17878fe3d01a2b45d5d0ded5)) +* update placeholder string ([3af093a](https://github.com/steel-dev/steel-python/commit/3af093a33381b2436287bdeb87ff0b3e0f997385)) + ## 0.16.0 (2026-02-06) Full Changelog: [v0.15.0...v0.16.0](https://github.com/steel-dev/steel-python/compare/v0.15.0...v0.16.0) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5c571fbe..fbd86d24 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -88,8 +88,7 @@ $ pip install ./path-to-wheel-file.whl Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. ```sh -# you will need npm installed -$ npx prism mock path/to/your/openapi.yml +$ ./scripts/mock ``` ```sh diff --git a/api.md b/api.md index 49ae21fe..8f08616f 100644 --- a/api.md +++ b/api.md @@ -71,7 +71,7 @@ Methods: - client.sessions.list(\*\*params) -> SyncSessionsCursor[Session] - client.sessions.computer(session_id, \*\*params) -> SessionComputerResponse - client.sessions.context(id) -> SessionContext -- client.sessions.events(id) -> SessionEventsResponse +- client.sessions.events(id, \*\*params) -> SessionEventsResponse - client.sessions.live_details(id) -> SessionLiveDetailsResponse - client.sessions.release(id) -> SessionReleaseResponse - client.sessions.release_all() -> SessionReleaseAllResponse diff --git a/pyproject.toml b/pyproject.toml index 10d2c916..8219a00b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "steel-sdk" -version = "0.16.0" +version = "0.17.0" description = "The official Python library for the steel API" dynamic = ["readme"] license = "Apache-2.0" @@ -69,7 +69,7 @@ format = { chain = [ # run formatting again to fix any inconsistencies when imports are stripped "format:ruff", ]} -"format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md" +"format:docs" = "bash -c 'python scripts/utils/ruffen-docs.py README.md $(find . -type f -name api.md)'" "format:ruff" = "ruff format" "lint" = { chain = [ diff --git a/requirements-dev.lock b/requirements-dev.lock index a25ec1b0..e55c751c 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -12,14 +12,14 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.13.2 +aiohttp==3.13.3 # via httpx-aiohttp # via steel-sdk aiosignal==1.4.0 # via aiohttp annotated-types==0.7.0 # via pydantic -anyio==4.12.0 +anyio==4.12.1 # via httpx # via steel-sdk argcomplete==3.6.3 @@ -31,7 +31,7 @@ attrs==25.4.0 # via nox backports-asyncio-runner==1.2.0 # via pytest-asyncio -certifi==2025.11.12 +certifi==2026.1.4 # via httpcore # via httpx colorlog==6.10.1 @@ -61,7 +61,7 @@ httpx==0.28.1 # via httpx-aiohttp # via respx # via steel-sdk -httpx-aiohttp==0.1.9 +httpx-aiohttp==0.1.12 # via steel-sdk humanize==4.13.0 # via nox @@ -69,7 +69,7 @@ idna==3.11 # via anyio # via httpx # via yarl -importlib-metadata==8.7.0 +importlib-metadata==8.7.1 iniconfig==2.1.0 # via pytest markdown-it-py==3.0.0 @@ -82,14 +82,14 @@ multidict==6.7.0 mypy==1.17.0 mypy-extensions==1.1.0 # via mypy -nodeenv==1.9.1 +nodeenv==1.10.0 # via pyright nox==2025.11.12 packaging==25.0 # via dependency-groups # via nox # via pytest -pathspec==0.12.1 +pathspec==1.0.3 # via mypy platformdirs==4.4.0 # via virtualenv @@ -115,13 +115,13 @@ python-dateutil==2.9.0.post0 # via time-machine respx==0.22.0 rich==14.2.0 -ruff==0.14.7 +ruff==0.14.13 six==1.17.0 # via python-dateutil sniffio==1.3.1 # via steel-sdk time-machine==2.19.0 -tomli==2.3.0 +tomli==2.4.0 # via dependency-groups # via mypy # via nox @@ -141,7 +141,7 @@ typing-extensions==4.15.0 # via virtualenv typing-inspection==0.4.2 # via pydantic -virtualenv==20.35.4 +virtualenv==20.36.1 # via nox yarl==1.22.0 # via aiohttp diff --git a/requirements.lock b/requirements.lock index 2ceaf4b6..b4878467 100644 --- a/requirements.lock +++ b/requirements.lock @@ -12,21 +12,21 @@ -e file:. aiohappyeyeballs==2.6.1 # via aiohttp -aiohttp==3.13.2 +aiohttp==3.13.3 # via httpx-aiohttp # via steel-sdk aiosignal==1.4.0 # via aiohttp annotated-types==0.7.0 # via pydantic -anyio==4.12.0 +anyio==4.12.1 # via httpx # via steel-sdk async-timeout==5.0.1 # via aiohttp attrs==25.4.0 # via aiohttp -certifi==2025.11.12 +certifi==2026.1.4 # via httpcore # via httpx distro==1.9.0 @@ -43,7 +43,7 @@ httpcore==1.0.9 httpx==0.28.1 # via httpx-aiohttp # via steel-sdk -httpx-aiohttp==0.1.9 +httpx-aiohttp==0.1.12 # via steel-sdk idna==3.11 # via anyio diff --git a/scripts/mock b/scripts/mock index 0b28f6ea..bcf3b392 100755 --- a/scripts/mock +++ b/scripts/mock @@ -21,11 +21,22 @@ echo "==> Starting mock server with URL ${URL}" # Run prism mock on the given spec if [ "$1" == "--daemon" ]; then + # Pre-install the package so the download doesn't eat into the startup timeout + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & - # Wait for server to come online + # Wait for server to come online (max 30s) echo -n "Waiting for server" + attempts=0 while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + attempts=$((attempts + 1)) + if [ "$attempts" -ge 300 ]; then + echo + echo "Timed out waiting for Prism server to start" + cat .prism.log + exit 1 + fi echo -n "." sleep 0.1 done diff --git a/src/steel/_response.py b/src/steel/_response.py index 4a4b497b..db760162 100644 --- a/src/steel/_response.py +++ b/src/steel/_response.py @@ -152,6 +152,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: ), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -162,6 +163,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=extract_stream_chunk_type(self._stream_cls), response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) @@ -175,6 +177,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: cast_to=cast_to, response=self.http_response, client=cast(Any, self._client), + options=self._options, ), ) diff --git a/src/steel/_streaming.py b/src/steel/_streaming.py index 3f2344fa..a5f00069 100644 --- a/src/steel/_streaming.py +++ b/src/steel/_streaming.py @@ -4,7 +4,7 @@ import json import inspect from types import TracebackType -from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, AsyncIterator, cast +from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, Optional, AsyncIterator, cast from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable import httpx @@ -13,6 +13,7 @@ if TYPE_CHECKING: from ._client import Steel, AsyncSteel + from ._models import FinalRequestOptions _T = TypeVar("_T") @@ -22,7 +23,7 @@ class Stream(Generic[_T]): """Provides the core interface to iterate over a synchronous stream response.""" response: httpx.Response - + _options: Optional[FinalRequestOptions] = None _decoder: SSEBytesDecoder def __init__( @@ -31,10 +32,12 @@ def __init__( cast_to: type[_T], response: httpx.Response, client: Steel, + options: Optional[FinalRequestOptions] = None, ) -> None: self.response = response self._cast_to = cast_to self._client = client + self._options = options self._decoder = client._make_sse_decoder() self._iterator = self.__stream__() @@ -85,7 +88,7 @@ class AsyncStream(Generic[_T]): """Provides the core interface to iterate over an asynchronous stream response.""" response: httpx.Response - + _options: Optional[FinalRequestOptions] = None _decoder: SSEDecoder | SSEBytesDecoder def __init__( @@ -94,10 +97,12 @@ def __init__( cast_to: type[_T], response: httpx.Response, client: AsyncSteel, + options: Optional[FinalRequestOptions] = None, ) -> None: self.response = response self._cast_to = cast_to self._client = client + self._options = options self._decoder = client._make_sse_decoder() self._iterator = self.__stream__() diff --git a/src/steel/_utils/_compat.py b/src/steel/_utils/_compat.py index dd703233..2c70b299 100644 --- a/src/steel/_utils/_compat.py +++ b/src/steel/_utils/_compat.py @@ -26,7 +26,7 @@ def is_union(tp: Optional[Type[Any]]) -> bool: else: import types - return tp is Union or tp is types.UnionType + return tp is Union or tp is types.UnionType # type: ignore[comparison-overlap] def is_typeddict(tp: Type[Any]) -> bool: diff --git a/src/steel/_version.py b/src/steel/_version.py index b8580980..06fdcfc6 100644 --- a/src/steel/_version.py +++ b/src/steel/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "steel" -__version__ = "0.16.0" # x-release-please-version +__version__ = "0.17.0" # x-release-please-version diff --git a/src/steel/resources/sessions/sessions.py b/src/steel/resources/sessions/sessions.py index a02b81c8..d54ca834 100644 --- a/src/steel/resources/sessions/sessions.py +++ b/src/steel/resources/sessions/sessions.py @@ -15,7 +15,7 @@ FilesResourceWithStreamingResponse, AsyncFilesResourceWithStreamingResponse, ) -from ...types import session_list_params, session_create_params, session_computer_params +from ...types import session_list_params, session_create_params, session_events_params, session_computer_params from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from ..._utils import required_args, maybe_transform, async_maybe_transform from .captchas import ( @@ -85,6 +85,7 @@ def create( debug_config: session_create_params.DebugConfig | Omit = omit, device_config: session_create_params.DeviceConfig | Omit = omit, dimensions: session_create_params.Dimensions | Omit = omit, + experimental_features: SequenceNotStr[str] | Omit = omit, extension_ids: SequenceNotStr[str] | Omit = omit, headless: bool | Omit = omit, is_selenium: bool | Omit = omit, @@ -126,6 +127,8 @@ def create( dimensions: Viewport and browser window dimensions for the session + experimental_features: Enable experimental features for the session. + extension_ids: Array of extension IDs to install in the session. Use ['all_ext'] to install all uploaded extensions. @@ -183,6 +186,7 @@ def create( "debug_config": debug_config, "device_config": device_config, "dimensions": dimensions, + "experimental_features": experimental_features, "extension_ids": extension_ids, "headless": headless, "is_selenium": is_selenium, @@ -716,6 +720,9 @@ def events( self, id: str, *, + compressed: bool | Omit = omit, + limit: int | Omit = omit, + pointer: str | Omit = omit, # 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, @@ -727,6 +734,12 @@ def events( This endpoint allows you to get the recorded session events in the RRWeb format Args: + compressed: Compress the events + + limit: Optional pagination limit + + pointer: Opaque pagination token. Pass the Next-Cursor header value to get the next page. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -740,7 +753,18 @@ def events( return self._get( f"/v1/sessions/{id}/events", options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "compressed": compressed, + "limit": limit, + "pointer": pointer, + }, + session_events_params.SessionEventsParams, + ), ), cast_to=SessionEventsResponse, ) @@ -868,6 +892,7 @@ async def create( debug_config: session_create_params.DebugConfig | Omit = omit, device_config: session_create_params.DeviceConfig | Omit = omit, dimensions: session_create_params.Dimensions | Omit = omit, + experimental_features: SequenceNotStr[str] | Omit = omit, extension_ids: SequenceNotStr[str] | Omit = omit, headless: bool | Omit = omit, is_selenium: bool | Omit = omit, @@ -909,6 +934,8 @@ async def create( dimensions: Viewport and browser window dimensions for the session + experimental_features: Enable experimental features for the session. + extension_ids: Array of extension IDs to install in the session. Use ['all_ext'] to install all uploaded extensions. @@ -966,6 +993,7 @@ async def create( "debug_config": debug_config, "device_config": device_config, "dimensions": dimensions, + "experimental_features": experimental_features, "extension_ids": extension_ids, "headless": headless, "is_selenium": is_selenium, @@ -1499,6 +1527,9 @@ async def events( self, id: str, *, + compressed: bool | Omit = omit, + limit: int | Omit = omit, + pointer: str | Omit = omit, # 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, @@ -1510,6 +1541,12 @@ async def events( This endpoint allows you to get the recorded session events in the RRWeb format Args: + compressed: Compress the events + + limit: Optional pagination limit + + pointer: Opaque pagination token. Pass the Next-Cursor header value to get the next page. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -1523,7 +1560,18 @@ async def events( return await self._get( f"/v1/sessions/{id}/events", options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "compressed": compressed, + "limit": limit, + "pointer": pointer, + }, + session_events_params.SessionEventsParams, + ), ), cast_to=SessionEventsResponse, ) diff --git a/src/steel/types/__init__.py b/src/steel/types/__init__.py index e33ce8a3..f2739660 100644 --- a/src/steel/types/__init__.py +++ b/src/steel/types/__init__.py @@ -19,6 +19,7 @@ from .profile_list_response import ProfileListResponse as ProfileListResponse from .profile_update_params import ProfileUpdateParams as ProfileUpdateParams from .session_create_params import SessionCreateParams as SessionCreateParams +from .session_events_params import SessionEventsParams as SessionEventsParams from .credential_list_params import CredentialListParams as CredentialListParams from .extension_list_response import ExtensionListResponse as ExtensionListResponse from .extension_update_params import ExtensionUpdateParams as ExtensionUpdateParams diff --git a/src/steel/types/session_create_params.py b/src/steel/types/session_create_params.py index b98d7f3f..cfb5d8fa 100644 --- a/src/steel/types/session_create_params.py +++ b/src/steel/types/session_create_params.py @@ -58,6 +58,9 @@ class SessionCreateParams(TypedDict, total=False): dimensions: Dimensions """Viewport and browser window dimensions for the session""" + experimental_features: Annotated[SequenceNotStr[str], PropertyInfo(alias="experimentalFeatures")] + """Enable experimental features for the session.""" + extension_ids: Annotated[SequenceNotStr[str], PropertyInfo(alias="extensionIds")] """Array of extension IDs to install in the session. diff --git a/src/steel/types/session_events_params.py b/src/steel/types/session_events_params.py new file mode 100644 index 00000000..d66997c4 --- /dev/null +++ b/src/steel/types/session_events_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["SessionEventsParams"] + + +class SessionEventsParams(TypedDict, total=False): + compressed: bool + """Compress the events""" + + limit: int + """Optional pagination limit""" + + pointer: str + """Opaque pagination token. + + Pass the Next-Cursor header value to get the next page. + """ diff --git a/src/steel/types/sessionslist.py b/src/steel/types/sessionslist.py index 05604e7e..58dfd383 100644 --- a/src/steel/types/sessionslist.py +++ b/src/steel/types/sessionslist.py @@ -177,5 +177,8 @@ class Sessionslist(BaseModel): sessions: List[Session] """List of browser sessions""" - total_count: int = FieldInfo(alias="totalCount") - """Total number of sessions matching the query""" + total_count: Optional[int] = FieldInfo(alias="totalCount", default=None) + """Total number of sessions matching the query. + + Only included for filtered queries (e.g. status=live). + """ diff --git a/tests/api_resources/sessions/test_files.py b/tests/api_resources/sessions/test_files.py index be2dbb03..ed641c70 100644 --- a/tests/api_resources/sessions/test_files.py +++ b/tests/api_resources/sessions/test_files.py @@ -263,7 +263,7 @@ def test_path_params_download_archive(self, client: Steel) -> None: def test_method_upload(self, client: Steel) -> None: file = client.sessions.files.upload( session_id="sessionId", - file=b"raw file contents", + file=b"Example data", ) assert_matches_type(File, file, path=["response"]) @@ -271,7 +271,7 @@ def test_method_upload(self, client: Steel) -> None: def test_method_upload_with_all_params(self, client: Steel) -> None: file = client.sessions.files.upload( session_id="sessionId", - file=b"raw file contents", + file=b"Example data", path="path", ) assert_matches_type(File, file, path=["response"]) @@ -280,7 +280,7 @@ def test_method_upload_with_all_params(self, client: Steel) -> None: def test_raw_response_upload(self, client: Steel) -> None: response = client.sessions.files.with_raw_response.upload( session_id="sessionId", - file=b"raw file contents", + file=b"Example data", ) assert response.is_closed is True @@ -292,7 +292,7 @@ def test_raw_response_upload(self, client: Steel) -> None: def test_streaming_response_upload(self, client: Steel) -> None: with client.sessions.files.with_streaming_response.upload( session_id="sessionId", - file=b"raw file contents", + file=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -307,7 +307,7 @@ def test_path_params_upload(self, client: Steel) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): client.sessions.files.with_raw_response.upload( session_id="", - file=b"raw file contents", + file=b"Example data", ) @@ -554,7 +554,7 @@ async def test_path_params_download_archive(self, async_client: AsyncSteel) -> N async def test_method_upload(self, async_client: AsyncSteel) -> None: file = await async_client.sessions.files.upload( session_id="sessionId", - file=b"raw file contents", + file=b"Example data", ) assert_matches_type(File, file, path=["response"]) @@ -562,7 +562,7 @@ async def test_method_upload(self, async_client: AsyncSteel) -> None: async def test_method_upload_with_all_params(self, async_client: AsyncSteel) -> None: file = await async_client.sessions.files.upload( session_id="sessionId", - file=b"raw file contents", + file=b"Example data", path="path", ) assert_matches_type(File, file, path=["response"]) @@ -571,7 +571,7 @@ async def test_method_upload_with_all_params(self, async_client: AsyncSteel) -> async def test_raw_response_upload(self, async_client: AsyncSteel) -> None: response = await async_client.sessions.files.with_raw_response.upload( session_id="sessionId", - file=b"raw file contents", + file=b"Example data", ) assert response.is_closed is True @@ -583,7 +583,7 @@ async def test_raw_response_upload(self, async_client: AsyncSteel) -> None: async def test_streaming_response_upload(self, async_client: AsyncSteel) -> None: async with async_client.sessions.files.with_streaming_response.upload( session_id="sessionId", - file=b"raw file contents", + file=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -598,5 +598,5 @@ async def test_path_params_upload(self, async_client: AsyncSteel) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `session_id` but received ''"): await async_client.sessions.files.with_raw_response.upload( session_id="", - file=b"raw file contents", + file=b"Example data", ) diff --git a/tests/api_resources/test_extensions.py b/tests/api_resources/test_extensions.py index b996a46b..e9ceafd5 100644 --- a/tests/api_resources/test_extensions.py +++ b/tests/api_resources/test_extensions.py @@ -34,7 +34,7 @@ def test_method_update(self, client: Steel) -> None: def test_method_update_with_all_params(self, client: Steel) -> None: extension = client.extensions.update( extension_id="extensionId", - file=b"raw file contents", + file=b"Example data", url="https://example.com", ) assert_matches_type(ExtensionUpdateResponse, extension, path=["response"]) @@ -204,7 +204,7 @@ def test_method_upload(self, client: Steel) -> None: @parametrize def test_method_upload_with_all_params(self, client: Steel) -> None: extension = client.extensions.upload( - file=b"raw file contents", + file=b"Example data", url="https://example.com", ) assert_matches_type(ExtensionUploadResponse, extension, path=["response"]) @@ -246,7 +246,7 @@ async def test_method_update(self, async_client: AsyncSteel) -> None: async def test_method_update_with_all_params(self, async_client: AsyncSteel) -> None: extension = await async_client.extensions.update( extension_id="extensionId", - file=b"raw file contents", + file=b"Example data", url="https://example.com", ) assert_matches_type(ExtensionUpdateResponse, extension, path=["response"]) @@ -416,7 +416,7 @@ async def test_method_upload(self, async_client: AsyncSteel) -> None: @parametrize async def test_method_upload_with_all_params(self, async_client: AsyncSteel) -> None: extension = await async_client.extensions.upload( - file=b"raw file contents", + file=b"Example data", url="https://example.com", ) assert_matches_type(ExtensionUploadResponse, extension, path=["response"]) diff --git a/tests/api_resources/test_files.py b/tests/api_resources/test_files.py index 5ca440d0..efcb9da6 100644 --- a/tests/api_resources/test_files.py +++ b/tests/api_resources/test_files.py @@ -141,14 +141,14 @@ def test_path_params_download(self, client: Steel) -> None: @parametrize def test_method_upload(self, client: Steel) -> None: file = client.files.upload( - file=b"raw file contents", + file=b"Example data", ) assert_matches_type(File, file, path=["response"]) @parametrize def test_method_upload_with_all_params(self, client: Steel) -> None: file = client.files.upload( - file=b"raw file contents", + file=b"Example data", path="path", ) assert_matches_type(File, file, path=["response"]) @@ -156,7 +156,7 @@ def test_method_upload_with_all_params(self, client: Steel) -> None: @parametrize def test_raw_response_upload(self, client: Steel) -> None: response = client.files.with_raw_response.upload( - file=b"raw file contents", + file=b"Example data", ) assert response.is_closed is True @@ -167,7 +167,7 @@ def test_raw_response_upload(self, client: Steel) -> None: @parametrize def test_streaming_response_upload(self, client: Steel) -> None: with client.files.with_streaming_response.upload( - file=b"raw file contents", + file=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -299,14 +299,14 @@ async def test_path_params_download(self, async_client: AsyncSteel) -> None: @parametrize async def test_method_upload(self, async_client: AsyncSteel) -> None: file = await async_client.files.upload( - file=b"raw file contents", + file=b"Example data", ) assert_matches_type(File, file, path=["response"]) @parametrize async def test_method_upload_with_all_params(self, async_client: AsyncSteel) -> None: file = await async_client.files.upload( - file=b"raw file contents", + file=b"Example data", path="path", ) assert_matches_type(File, file, path=["response"]) @@ -314,7 +314,7 @@ async def test_method_upload_with_all_params(self, async_client: AsyncSteel) -> @parametrize async def test_raw_response_upload(self, async_client: AsyncSteel) -> None: response = await async_client.files.with_raw_response.upload( - file=b"raw file contents", + file=b"Example data", ) assert response.is_closed is True @@ -325,7 +325,7 @@ async def test_raw_response_upload(self, async_client: AsyncSteel) -> None: @parametrize async def test_streaming_response_upload(self, async_client: AsyncSteel) -> None: async with async_client.files.with_streaming_response.upload( - file=b"raw file contents", + file=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_profiles.py b/tests/api_resources/test_profiles.py index 24a3cd08..52324e1a 100644 --- a/tests/api_resources/test_profiles.py +++ b/tests/api_resources/test_profiles.py @@ -25,14 +25,14 @@ class TestProfiles: @parametrize def test_method_create(self, client: Steel) -> None: profile = client.profiles.create( - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) assert_matches_type(ProfileCreateResponse, profile, path=["response"]) @parametrize def test_method_create_with_all_params(self, client: Steel) -> None: profile = client.profiles.create( - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", dimensions={ "height": 0, "width": 0, @@ -45,7 +45,7 @@ def test_method_create_with_all_params(self, client: Steel) -> None: @parametrize def test_raw_response_create(self, client: Steel) -> None: response = client.profiles.with_raw_response.create( - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) assert response.is_closed is True @@ -56,7 +56,7 @@ def test_raw_response_create(self, client: Steel) -> None: @parametrize def test_streaming_response_create(self, client: Steel) -> None: with client.profiles.with_streaming_response.create( - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -70,7 +70,7 @@ def test_streaming_response_create(self, client: Steel) -> None: def test_method_update(self, client: Steel) -> None: profile = client.profiles.update( id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) assert_matches_type(ProfileUpdateResponse, profile, path=["response"]) @@ -78,7 +78,7 @@ def test_method_update(self, client: Steel) -> None: def test_method_update_with_all_params(self, client: Steel) -> None: profile = client.profiles.update( id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", dimensions={ "height": 0, "width": 0, @@ -92,7 +92,7 @@ def test_method_update_with_all_params(self, client: Steel) -> None: def test_raw_response_update(self, client: Steel) -> None: response = client.profiles.with_raw_response.update( id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) assert response.is_closed is True @@ -104,7 +104,7 @@ def test_raw_response_update(self, client: Steel) -> None: def test_streaming_response_update(self, client: Steel) -> None: with client.profiles.with_streaming_response.update( id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -119,7 +119,7 @@ def test_path_params_update(self, client: Steel) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): client.profiles.with_raw_response.update( id="", - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) @parametrize @@ -194,14 +194,14 @@ class TestAsyncProfiles: @parametrize async def test_method_create(self, async_client: AsyncSteel) -> None: profile = await async_client.profiles.create( - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) assert_matches_type(ProfileCreateResponse, profile, path=["response"]) @parametrize async def test_method_create_with_all_params(self, async_client: AsyncSteel) -> None: profile = await async_client.profiles.create( - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", dimensions={ "height": 0, "width": 0, @@ -214,7 +214,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncSteel) -> @parametrize async def test_raw_response_create(self, async_client: AsyncSteel) -> None: response = await async_client.profiles.with_raw_response.create( - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) assert response.is_closed is True @@ -225,7 +225,7 @@ async def test_raw_response_create(self, async_client: AsyncSteel) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncSteel) -> None: async with async_client.profiles.with_streaming_response.create( - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -239,7 +239,7 @@ async def test_streaming_response_create(self, async_client: AsyncSteel) -> None async def test_method_update(self, async_client: AsyncSteel) -> None: profile = await async_client.profiles.update( id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) assert_matches_type(ProfileUpdateResponse, profile, path=["response"]) @@ -247,7 +247,7 @@ async def test_method_update(self, async_client: AsyncSteel) -> None: async def test_method_update_with_all_params(self, async_client: AsyncSteel) -> None: profile = await async_client.profiles.update( id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", dimensions={ "height": 0, "width": 0, @@ -261,7 +261,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncSteel) -> async def test_raw_response_update(self, async_client: AsyncSteel) -> None: response = await async_client.profiles.with_raw_response.update( id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) assert response.is_closed is True @@ -273,7 +273,7 @@ async def test_raw_response_update(self, async_client: AsyncSteel) -> None: async def test_streaming_response_update(self, async_client: AsyncSteel) -> None: async with async_client.profiles.with_streaming_response.update( id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -288,7 +288,7 @@ async def test_path_params_update(self, async_client: AsyncSteel) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): await async_client.profiles.with_raw_response.update( id="", - user_data_dir=b"raw file contents", + user_data_dir=b"Example data", ) @parametrize diff --git a/tests/api_resources/test_sessions.py b/tests/api_resources/test_sessions.py index 05d575d7..9fabc926 100644 --- a/tests/api_resources/test_sessions.py +++ b/tests/api_resources/test_sessions.py @@ -52,6 +52,7 @@ def test_method_create_with_all_params(self, client: Steel) -> None: "height": -9007199254740991, "width": -9007199254740991, }, + experimental_features=["string"], extension_ids=["string"], headless=True, is_selenium=True, @@ -747,14 +748,24 @@ def test_path_params_context(self, client: Steel) -> None: @parametrize def test_method_events(self, client: Steel) -> None: session = client.sessions.events( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(SessionEventsResponse, session, path=["response"]) + + @parametrize + def test_method_events_with_all_params(self, client: Steel) -> None: + session = client.sessions.events( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + compressed=True, + limit=1, + pointer="pointer", ) assert_matches_type(SessionEventsResponse, session, path=["response"]) @parametrize def test_raw_response_events(self, client: Steel) -> None: response = client.sessions.with_raw_response.events( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True @@ -765,7 +776,7 @@ def test_raw_response_events(self, client: Steel) -> None: @parametrize def test_streaming_response_events(self, client: Steel) -> None: with client.sessions.with_streaming_response.events( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -779,7 +790,7 @@ def test_streaming_response_events(self, client: Steel) -> None: def test_path_params_events(self, client: Steel) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): client.sessions.with_raw_response.events( - "", + id="", ) @parametrize @@ -913,6 +924,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncSteel) -> "height": -9007199254740991, "width": -9007199254740991, }, + experimental_features=["string"], extension_ids=["string"], headless=True, is_selenium=True, @@ -1608,14 +1620,24 @@ async def test_path_params_context(self, async_client: AsyncSteel) -> None: @parametrize async def test_method_events(self, async_client: AsyncSteel) -> None: session = await async_client.sessions.events( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(SessionEventsResponse, session, path=["response"]) + + @parametrize + async def test_method_events_with_all_params(self, async_client: AsyncSteel) -> None: + session = await async_client.sessions.events( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + compressed=True, + limit=1, + pointer="pointer", ) assert_matches_type(SessionEventsResponse, session, path=["response"]) @parametrize async def test_raw_response_events(self, async_client: AsyncSteel) -> None: response = await async_client.sessions.with_raw_response.events( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) assert response.is_closed is True @@ -1626,7 +1648,7 @@ async def test_raw_response_events(self, async_client: AsyncSteel) -> None: @parametrize async def test_streaming_response_events(self, async_client: AsyncSteel) -> None: async with async_client.sessions.with_streaming_response.events( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -1640,7 +1662,7 @@ async def test_streaming_response_events(self, async_client: AsyncSteel) -> None async def test_path_params_events(self, async_client: AsyncSteel) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): await async_client.sessions.with_raw_response.events( - "", + id="", ) @parametrize diff --git a/tests/test_client.py b/tests/test_client.py index fe612e5a..410bcac6 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -904,6 +904,14 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + # Delete in case our environment has any proxy env vars set + monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) client = DefaultHttpxClient() @@ -1756,6 +1764,14 @@ async def test_get_platform(self) -> None: async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: # Test that the proxy environment variables are set correctly monkeypatch.setenv("HTTPS_PROXY", "https://example.org") + # Delete in case our environment has any proxy env vars set + monkeypatch.delenv("HTTP_PROXY", raising=False) + monkeypatch.delenv("ALL_PROXY", raising=False) + monkeypatch.delenv("NO_PROXY", raising=False) + monkeypatch.delenv("http_proxy", raising=False) + monkeypatch.delenv("https_proxy", raising=False) + monkeypatch.delenv("all_proxy", raising=False) + monkeypatch.delenv("no_proxy", raising=False) client = DefaultAsyncHttpxClient()