diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 55d20255c..ff261bad7 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -3,7 +3,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} USER vscode -RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.35.0" RYE_INSTALL_OPTION="--yes" bash +RUN curl -sSf https://rye.astral.sh/get | RYE_VERSION="0.44.0" RYE_INSTALL_OPTION="--yes" bash ENV PATH=/home/vscode/.rye/shims:$PATH RUN echo "[[ -d .venv ]] && source .venv/bin/activate || export PATH=\$PATH" >> /home/vscode/.bashrc diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c8a8a4f72..3b286e5ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: curl -sSf https://rye.astral.sh/get | bash echo "$HOME/.rye/shims" >> $GITHUB_PATH env: - RYE_VERSION: '0.35.0' + RYE_VERSION: '0.44.0' RYE_INSTALL_OPTION: '--yes' - name: Install dependencies @@ -42,7 +42,7 @@ jobs: curl -sSf https://rye.astral.sh/get | bash echo "$HOME/.rye/shims" >> $GITHUB_PATH env: - RYE_VERSION: '0.35.0' + RYE_VERSION: '0.44.0' RYE_INSTALL_OPTION: '--yes' - name: Bootstrap diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml index a56e643fb..fbcdea446 100644 --- a/.github/workflows/publish-pypi.yml +++ b/.github/workflows/publish-pypi.yml @@ -21,7 +21,7 @@ jobs: curl -sSf https://rye.astral.sh/get | bash echo "$HOME/.rye/shims" >> $GITHUB_PATH env: - RYE_VERSION: '0.35.0' + RYE_VERSION: '0.44.0' RYE_INSTALL_OPTION: '--yes' - name: Publish to PyPI diff --git a/.release-please-manifest.json b/.release-please-manifest.json index caf5ca3f3..59acac471 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.26.0" + ".": "0.27.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 08c183bf8..4dd4711f3 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 78 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-4ccbc7c04012cbcca678f13e39f66bb770b8b3a9d6f1815ce1b9c20fee099128.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai%2Frunloop-1c6045460c43f65b30ffcef9f707e8d71dca568bf8d208347a6046a6f03ff239.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 637f0c1d3..f6ac326d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## 0.27.0 (2025-03-21) + +Full Changelog: [v0.26.0...v0.27.0](https://github.com/runloopai/api-client-python/compare/v0.26.0...v0.27.0) + +### Features + +* **api:** api update ([#573](https://github.com/runloopai/api-client-python/issues/573)) ([091f833](https://github.com/runloopai/api-client-python/commit/091f833d80096bb0470d505c0a0145648e52819b)) + + +### Bug Fixes + +* **ci:** ensure pip is always available ([#571](https://github.com/runloopai/api-client-python/issues/571)) ([ddb9362](https://github.com/runloopai/api-client-python/commit/ddb93629704f116cafb2123dc8b302ddff883bb8)) +* **ci:** remove publishing patch ([#572](https://github.com/runloopai/api-client-python/issues/572)) ([c71815a](https://github.com/runloopai/api-client-python/commit/c71815aaaf47e404e1bf3d44c6b26b5ed0b05054)) +* **types:** handle more discriminated union shapes ([#570](https://github.com/runloopai/api-client-python/issues/570)) ([297cfbe](https://github.com/runloopai/api-client-python/commit/297cfbe93bfdcbbafd44a4501d5a81a7fb1651bd)) + + +### Chores + +* **internal:** bump rye to 0.44.0 ([#569](https://github.com/runloopai/api-client-python/issues/569)) ([dd5b79a](https://github.com/runloopai/api-client-python/commit/dd5b79a221fff5b38fdbd655d78254fe7140fd73)) +* **internal:** remove extra empty newlines ([#567](https://github.com/runloopai/api-client-python/issues/567)) ([49f34bd](https://github.com/runloopai/api-client-python/commit/49f34bd0b733f2a10592fff098d379501df3ac86)) + + +### Documentation + +* revise readme docs about nested params ([#564](https://github.com/runloopai/api-client-python/issues/564)) ([a2df5d3](https://github.com/runloopai/api-client-python/commit/a2df5d3c9b32ab941ee83d3f5cac8b874b7bbe28)) + ## 0.26.0 (2025-03-04) Full Changelog: [v0.25.0...v0.26.0](https://github.com/runloopai/api-client-python/compare/v0.25.0...v0.26.0) diff --git a/README.md b/README.md index 643113029..ec6ee93f1 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,33 @@ for devbox in first_page.devboxes: # Remove `await` for non-async usage. ``` +## Nested params + +Nested parameters are dictionaries, typed using `TypedDict`, for example: + +```python +from runloop_api_client import Runloop + +client = Runloop() + +blueprint_view = client.blueprints.create( + name="name", + launch_parameters={ + "after_idle": { + "idle_time_seconds": 0, + "on_idle": "shutdown", + }, + "available_ports": [0], + "custom_cpu_cores": 0, + "custom_gb_memory": 0, + "keep_alive_time_seconds": 0, + "launch_commands": ["string"], + "resource_size_request": "SMALL", + }, +) +print(blueprint_view.launch_parameters) +``` + ## File uploads Request parameters that correspond to file uploads can be passed as `bytes`, a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`. diff --git a/bin/publish-pypi b/bin/publish-pypi index 05bfccbb7..826054e92 100644 --- a/bin/publish-pypi +++ b/bin/publish-pypi @@ -3,7 +3,4 @@ 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 diff --git a/pyproject.toml b/pyproject.toml index 7b42ba0af..103cd4f9c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "runloop_api_client" -version = "0.26.0" +version = "0.27.0" description = "The official Python library for the runloop API" dynamic = ["readme"] license = "MIT" @@ -38,7 +38,6 @@ Homepage = "https://github.com/runloopai/api-client-python" Repository = "https://github.com/runloopai/api-client-python" - [tool.rye] managed = true # version pins are in requirements-dev.lock @@ -87,7 +86,7 @@ typecheck = { chain = [ "typecheck:mypy" = "mypy ." [build-system] -requires = ["hatchling", "hatch-fancy-pypi-readme"] +requires = ["hatchling==1.26.3", "hatch-fancy-pypi-readme"] build-backend = "hatchling.build" [tool.hatch.build] @@ -152,7 +151,6 @@ reportImplicitOverride = true reportImportCycles = false reportPrivateUsage = false - [tool.ruff] line-length = 120 output-format = "grouped" diff --git a/scripts/test b/scripts/test index 4fa5698b8..2b8784567 100755 --- a/scripts/test +++ b/scripts/test @@ -52,6 +52,8 @@ else echo fi +export DEFER_PYDANTIC_BUILD=false + echo "==> Running tests" rye run pytest "$@" diff --git a/src/runloop_api_client/_models.py b/src/runloop_api_client/_models.py index c4401ff86..b51a1bf5f 100644 --- a/src/runloop_api_client/_models.py +++ b/src/runloop_api_client/_models.py @@ -65,7 +65,7 @@ from ._constants import RAW_RESPONSE_HEADER if TYPE_CHECKING: - from pydantic_core.core_schema import ModelField, LiteralSchema, ModelFieldsSchema + from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema __all__ = ["BaseModel", "GenericModel"] @@ -646,15 +646,18 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelField | None: schema = model.__pydantic_core_schema__ + if schema["type"] == "definitions": + schema = schema["schema"] + if schema["type"] != "model": return None + schema = cast("ModelSchema", schema) fields_schema = schema["schema"] if fields_schema["type"] != "model-fields": return None fields_schema = cast("ModelFieldsSchema", fields_schema) - field = fields_schema["fields"].get(field_name) if not field: return None diff --git a/src/runloop_api_client/_version.py b/src/runloop_api_client/_version.py index 66357b018..798803838 100644 --- a/src/runloop_api_client/_version.py +++ b/src/runloop_api_client/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "runloop_api_client" -__version__ = "0.26.0" # x-release-please-version +__version__ = "0.27.0" # x-release-please-version diff --git a/src/runloop_api_client/resources/scenarios/runs.py b/src/runloop_api_client/resources/scenarios/runs.py index 170b7c12c..cabd8518f 100644 --- a/src/runloop_api_client/resources/scenarios/runs.py +++ b/src/runloop_api_client/resources/scenarios/runs.py @@ -141,8 +141,10 @@ def complete( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, ) -> ScenarioRunView: - """ - Complete a currently running ScenarioRun. + """Complete a currently running ScenarioRun. + + Calling complete will shutdown + underlying Devbox resource. Args: extra_headers: Send extra headers @@ -467,8 +469,10 @@ async def complete( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, idempotency_key: str | None = None, ) -> ScenarioRunView: - """ - Complete a currently running ScenarioRun. + """Complete a currently running ScenarioRun. + + Calling complete will shutdown + underlying Devbox resource. Args: extra_headers: Send extra headers diff --git a/src/runloop_api_client/types/benchmark_list_view.py b/src/runloop_api_client/types/benchmark_list_view.py index 40ebd65dd..225002840 100644 --- a/src/runloop_api_client/types/benchmark_list_view.py +++ b/src/runloop_api_client/types/benchmark_list_view.py @@ -14,4 +14,6 @@ class BenchmarkListView(BaseModel): has_more: bool + remaining_count: int + total_count: int diff --git a/src/runloop_api_client/types/benchmark_run_list_view.py b/src/runloop_api_client/types/benchmark_run_list_view.py index 4a8a1fda0..0d0ca11e1 100644 --- a/src/runloop_api_client/types/benchmark_run_list_view.py +++ b/src/runloop_api_client/types/benchmark_run_list_view.py @@ -11,6 +11,8 @@ class BenchmarkRunListView(BaseModel): has_more: bool + remaining_count: int + runs: List[BenchmarkRunView] """List of BenchmarkRuns matching filter.""" diff --git a/src/runloop_api_client/types/blueprint_list_view.py b/src/runloop_api_client/types/blueprint_list_view.py index 57f845c95..ba7c6066f 100644 --- a/src/runloop_api_client/types/blueprint_list_view.py +++ b/src/runloop_api_client/types/blueprint_list_view.py @@ -14,4 +14,6 @@ class BlueprintListView(BaseModel): has_more: bool + remaining_count: int + total_count: int diff --git a/src/runloop_api_client/types/devbox_list_view.py b/src/runloop_api_client/types/devbox_list_view.py index 332b737f3..f4f266240 100644 --- a/src/runloop_api_client/types/devbox_list_view.py +++ b/src/runloop_api_client/types/devbox_list_view.py @@ -14,4 +14,6 @@ class DevboxListView(BaseModel): has_more: bool + remaining_count: int + total_count: int diff --git a/src/runloop_api_client/types/devbox_snapshot_list_view.py b/src/runloop_api_client/types/devbox_snapshot_list_view.py index 6bb1eb530..3e687f0cc 100644 --- a/src/runloop_api_client/types/devbox_snapshot_list_view.py +++ b/src/runloop_api_client/types/devbox_snapshot_list_view.py @@ -11,6 +11,8 @@ class DevboxSnapshotListView(BaseModel): has_more: bool + remaining_count: int + snapshots: List[DevboxSnapshotView] """List of snapshots matching filter.""" diff --git a/src/runloop_api_client/types/repository_connection_list_view.py b/src/runloop_api_client/types/repository_connection_list_view.py index 4ad5a10ec..8085c4718 100644 --- a/src/runloop_api_client/types/repository_connection_list_view.py +++ b/src/runloop_api_client/types/repository_connection_list_view.py @@ -11,6 +11,8 @@ class RepositoryConnectionListView(BaseModel): has_more: bool + remaining_count: int + repositories: List[RepositoryConnectionView] """List of repositories matching filter.""" diff --git a/src/runloop_api_client/types/scenario_list_view.py b/src/runloop_api_client/types/scenario_list_view.py index 9afe534cf..b11272649 100644 --- a/src/runloop_api_client/types/scenario_list_view.py +++ b/src/runloop_api_client/types/scenario_list_view.py @@ -11,6 +11,8 @@ class ScenarioListView(BaseModel): has_more: bool + remaining_count: int + scenarios: List[ScenarioView] """List of Scenarios matching filter.""" diff --git a/src/runloop_api_client/types/scenario_run_list_view.py b/src/runloop_api_client/types/scenario_run_list_view.py index 73494f84c..db0d16d31 100644 --- a/src/runloop_api_client/types/scenario_run_list_view.py +++ b/src/runloop_api_client/types/scenario_run_list_view.py @@ -11,6 +11,8 @@ class ScenarioRunListView(BaseModel): has_more: bool + remaining_count: int + runs: List[ScenarioRunView] """List of ScenarioRuns matching filter.""" diff --git a/src/runloop_api_client/types/scoring_function.py b/src/runloop_api_client/types/scoring_function.py index f7a2a6e0d..e3eddf554 100644 --- a/src/runloop_api_client/types/scoring_function.py +++ b/src/runloop_api_client/types/scoring_function.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional from .._models import BaseModel @@ -11,12 +10,10 @@ class ScoringFunction(BaseModel): name: str """Name of scoring function. Names must only contain [a-zA-Z0-9_-].""" - type: str - """Type of the scoring function. + scoring_function: ScoringFunction + """The scoring function to use for evaluating this scenario. - Use 'bash' as type and fill out 'bash_script' field for scoring via custom bash - scripts. Otherwise use a type corresponding to a custom scorer function or a - public Runloop scorer type. + The type field determines which built-in function to use. """ weight: float @@ -24,16 +21,3 @@ class ScoringFunction(BaseModel): Weights of all scoring functions should sum to 1.0. """ - - bash_script: Optional[str] = None - """ - A single bash script that sets up the environment, scores, and prints the final - score to standard out. Score should be a float between 0.0 and 1.0, and look - like "score=[0.0..1.0]. - """ - - scorer_params: Optional[object] = None - """ - Additional JSON structured context to pass to the scoring function if using - custom scorer. - """ diff --git a/src/runloop_api_client/types/scoring_function_param.py b/src/runloop_api_client/types/scoring_function_param.py index 5bcbacc58..264bf612c 100644 --- a/src/runloop_api_client/types/scoring_function_param.py +++ b/src/runloop_api_client/types/scoring_function_param.py @@ -2,39 +2,120 @@ from __future__ import annotations -from typing import Optional -from typing_extensions import Required, TypedDict +from typing import Union, Iterable, Optional +from typing_extensions import Literal, Required, TypeAlias, TypedDict -__all__ = ["ScoringFunctionParam"] +__all__ = [ + "ScoringFunctionParam", + "ScoringFunction", + "ScoringFunctionAstGrepScoringFunction", + "ScoringFunctionBashScriptScoringFunction", + "ScoringFunctionCommandScoringFunction", + "ScoringFunctionCustomScoringFunction", + "ScoringFunctionPythonScriptScoringFunction", + "ScoringFunctionTestBasedScoringFunction", + "ScoringFunctionTestBasedScoringFunctionTestFile", +] -class ScoringFunctionParam(TypedDict, total=False): - name: Required[str] - """Name of scoring function. Names must only contain [a-zA-Z0-9_-].""" +class ScoringFunctionAstGrepScoringFunction(TypedDict, total=False): + pattern: Required[str] + """AST pattern to match.""" - type: Required[str] - """Type of the scoring function. + search_directory: Required[str] + """The path to search.""" - Use 'bash' as type and fill out 'bash_script' field for scoring via custom bash - scripts. Otherwise use a type corresponding to a custom scorer function or a - public Runloop scorer type. - """ + type: Required[Literal["ast_grep_scorer"]] - weight: Required[float] - """Weight to apply to scoring function score. + lang: str + """The language of the pattern.""" - Weights of all scoring functions should sum to 1.0. - """ - bash_script: Optional[str] +class ScoringFunctionBashScriptScoringFunction(TypedDict, total=False): + type: Required[Literal["bash_script_scorer"]] + + bash_script: str """ A single bash script that sets up the environment, scores, and prints the final score to standard out. Score should be a float between 0.0 and 1.0, and look like "score=[0.0..1.0]. """ + +class ScoringFunctionCommandScoringFunction(TypedDict, total=False): + type: Required[Literal["command_scorer"]] + + command: str + """The command to execute.""" + + +class ScoringFunctionCustomScoringFunction(TypedDict, total=False): + type: Required[Literal["custom_scorer"]] + scorer_params: Optional[object] + """Additional JSON structured context to pass to the scoring function.""" + + +class ScoringFunctionPythonScriptScoringFunction(TypedDict, total=False): + python_script: Required[str] + """Python script to be run. + + The script should output the score to standard out as a float between 0.0 and + 1.0. """ - Additional JSON structured context to pass to the scoring function if using - custom scorer. + + type: Required[Literal["python_script_scorer"]] + + requirements_contents: str + """Package dependencies to be installed. + + The requirements should be a valid requirements.txt file. + """ + + +class ScoringFunctionTestBasedScoringFunctionTestFile(TypedDict, total=False): + file_contents: str + """Content of the test file""" + + file_path: str + """ + Path to write content of the test file, relative to your environment's working + directory + """ + + +class ScoringFunctionTestBasedScoringFunction(TypedDict, total=False): + type: Required[Literal["test_based_scorer"]] + + test_command: str + """The command to execute for running the tests""" + + test_files: Iterable[ScoringFunctionTestBasedScoringFunctionTestFile] + """List of test files to create""" + + +ScoringFunction: TypeAlias = Union[ + ScoringFunctionAstGrepScoringFunction, + ScoringFunctionBashScriptScoringFunction, + ScoringFunctionCommandScoringFunction, + ScoringFunctionCustomScoringFunction, + ScoringFunctionPythonScriptScoringFunction, + ScoringFunctionTestBasedScoringFunction, +] + + +class ScoringFunctionParam(TypedDict, total=False): + name: Required[str] + """Name of scoring function. Names must only contain [a-zA-Z0-9_-].""" + + scoring_function: Required[ScoringFunction] + """The scoring function to use for evaluating this scenario. + + The type field determines which built-in function to use. + """ + + weight: Required[float] + """Weight to apply to scoring function score. + + Weights of all scoring functions should sum to 1.0. """ diff --git a/src/runloop_api_client/types/shared/launch_parameters.py b/src/runloop_api_client/types/shared/launch_parameters.py index 5113a18a0..6a93c7ef5 100644 --- a/src/runloop_api_client/types/shared/launch_parameters.py +++ b/src/runloop_api_client/types/shared/launch_parameters.py @@ -23,6 +23,12 @@ class LaunchParameters(BaseModel): 'createTunnel' API. """ + custom_cpu_cores: Optional[int] = None + """custom resource size, number of cpu cores, must be multiple of 2.""" + + custom_gb_memory: Optional[int] = None + """custom memory size, number in Gi, must be a multiple of 2.""" + keep_alive_time_seconds: Optional[int] = None """Time in seconds after which Devbox will automatically shutdown. diff --git a/src/runloop_api_client/types/shared_params/launch_parameters.py b/src/runloop_api_client/types/shared_params/launch_parameters.py index 320fa92d1..549b3dbaa 100644 --- a/src/runloop_api_client/types/shared_params/launch_parameters.py +++ b/src/runloop_api_client/types/shared_params/launch_parameters.py @@ -24,6 +24,12 @@ class LaunchParameters(TypedDict, total=False): 'createTunnel' API. """ + custom_cpu_cores: Optional[int] + """custom resource size, number of cpu cores, must be multiple of 2.""" + + custom_gb_memory: Optional[int] + """custom memory size, number in Gi, must be a multiple of 2.""" + keep_alive_time_seconds: Optional[int] """Time in seconds after which Devbox will automatically shutdown. diff --git a/tests/api_resources/scenarios/test_scorers.py b/tests/api_resources/scenarios/test_scorers.py index 4c04211da..f848d8798 100644 --- a/tests/api_resources/scenarios/test_scorers.py +++ b/tests/api_resources/scenarios/test_scorers.py @@ -196,6 +196,8 @@ def test_method_validate_with_all_params(self, client: Runloop) -> None: "on_idle": "shutdown", }, "available_ports": [0], + "custom_cpu_cores": 0, + "custom_gb_memory": 0, "keep_alive_time_seconds": 0, "launch_commands": ["string"], "resource_size_request": "SMALL", @@ -417,6 +419,8 @@ async def test_method_validate_with_all_params(self, async_client: AsyncRunloop) "on_idle": "shutdown", }, "available_ports": [0], + "custom_cpu_cores": 0, + "custom_gb_memory": 0, "keep_alive_time_seconds": 0, "launch_commands": ["string"], "resource_size_request": "SMALL", diff --git a/tests/api_resources/test_blueprints.py b/tests/api_resources/test_blueprints.py index 0fc433dba..5a9fc89e9 100644 --- a/tests/api_resources/test_blueprints.py +++ b/tests/api_resources/test_blueprints.py @@ -49,6 +49,8 @@ def test_method_create_with_all_params(self, client: Runloop) -> None: "on_idle": "shutdown", }, "available_ports": [0], + "custom_cpu_cores": 0, + "custom_gb_memory": 0, "keep_alive_time_seconds": 0, "launch_commands": ["string"], "resource_size_request": "SMALL", @@ -218,6 +220,8 @@ def test_method_preview_with_all_params(self, client: Runloop) -> None: "on_idle": "shutdown", }, "available_ports": [0], + "custom_cpu_cores": 0, + "custom_gb_memory": 0, "keep_alive_time_seconds": 0, "launch_commands": ["string"], "resource_size_request": "SMALL", @@ -281,6 +285,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncRunloop) - "on_idle": "shutdown", }, "available_ports": [0], + "custom_cpu_cores": 0, + "custom_gb_memory": 0, "keep_alive_time_seconds": 0, "launch_commands": ["string"], "resource_size_request": "SMALL", @@ -450,6 +456,8 @@ async def test_method_preview_with_all_params(self, async_client: AsyncRunloop) "on_idle": "shutdown", }, "available_ports": [0], + "custom_cpu_cores": 0, + "custom_gb_memory": 0, "keep_alive_time_seconds": 0, "launch_commands": ["string"], "resource_size_request": "SMALL", diff --git a/tests/api_resources/test_devboxes.py b/tests/api_resources/test_devboxes.py index e3faa298a..ce6638c01 100644 --- a/tests/api_resources/test_devboxes.py +++ b/tests/api_resources/test_devboxes.py @@ -65,6 +65,8 @@ def test_method_create_with_all_params(self, client: Runloop) -> None: "on_idle": "shutdown", }, "available_ports": [0], + "custom_cpu_cores": 0, + "custom_gb_memory": 0, "keep_alive_time_seconds": 0, "launch_commands": ["string"], "resource_size_request": "SMALL", @@ -938,6 +940,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncRunloop) - "on_idle": "shutdown", }, "available_ports": [0], + "custom_cpu_cores": 0, + "custom_gb_memory": 0, "keep_alive_time_seconds": 0, "launch_commands": ["string"], "resource_size_request": "SMALL", diff --git a/tests/api_resources/test_scenarios.py b/tests/api_resources/test_scenarios.py index 218ebb542..8977f886b 100644 --- a/tests/api_resources/test_scenarios.py +++ b/tests/api_resources/test_scenarios.py @@ -30,7 +30,11 @@ def test_method_create(self, client: Runloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] @@ -50,10 +54,13 @@ def test_method_create_with_all_params(self, client: Runloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + "lang": "lang", + }, "weight": 0, - "bash_script": "bash_script", - "scorer_params": {}, } ] }, @@ -65,6 +72,8 @@ def test_method_create_with_all_params(self, client: Runloop) -> None: "on_idle": "shutdown", }, "available_ports": [0], + "custom_cpu_cores": 0, + "custom_gb_memory": 0, "keep_alive_time_seconds": 0, "launch_commands": ["string"], "resource_size_request": "SMALL", @@ -87,7 +96,11 @@ def test_raw_response_create(self, client: Runloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] @@ -108,7 +121,11 @@ def test_streaming_response_create(self, client: Runloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] @@ -170,7 +187,11 @@ def test_method_update(self, client: Runloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] @@ -191,10 +212,13 @@ def test_method_update_with_all_params(self, client: Runloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + "lang": "lang", + }, "weight": 0, - "bash_script": "bash_script", - "scorer_params": {}, } ] }, @@ -206,6 +230,8 @@ def test_method_update_with_all_params(self, client: Runloop) -> None: "on_idle": "shutdown", }, "available_ports": [0], + "custom_cpu_cores": 0, + "custom_gb_memory": 0, "keep_alive_time_seconds": 0, "launch_commands": ["string"], "resource_size_request": "SMALL", @@ -229,7 +255,11 @@ def test_raw_response_update(self, client: Runloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] @@ -251,7 +281,11 @@ def test_streaming_response_update(self, client: Runloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] @@ -276,7 +310,11 @@ def test_path_params_update(self, client: Runloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] @@ -405,7 +443,11 @@ async def test_method_create(self, async_client: AsyncRunloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] @@ -425,10 +467,13 @@ async def test_method_create_with_all_params(self, async_client: AsyncRunloop) - "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + "lang": "lang", + }, "weight": 0, - "bash_script": "bash_script", - "scorer_params": {}, } ] }, @@ -440,6 +485,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncRunloop) - "on_idle": "shutdown", }, "available_ports": [0], + "custom_cpu_cores": 0, + "custom_gb_memory": 0, "keep_alive_time_seconds": 0, "launch_commands": ["string"], "resource_size_request": "SMALL", @@ -462,7 +509,11 @@ async def test_raw_response_create(self, async_client: AsyncRunloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] @@ -483,7 +534,11 @@ async def test_streaming_response_create(self, async_client: AsyncRunloop) -> No "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] @@ -545,7 +600,11 @@ async def test_method_update(self, async_client: AsyncRunloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] @@ -566,10 +625,13 @@ async def test_method_update_with_all_params(self, async_client: AsyncRunloop) - "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + "lang": "lang", + }, "weight": 0, - "bash_script": "bash_script", - "scorer_params": {}, } ] }, @@ -581,6 +643,8 @@ async def test_method_update_with_all_params(self, async_client: AsyncRunloop) - "on_idle": "shutdown", }, "available_ports": [0], + "custom_cpu_cores": 0, + "custom_gb_memory": 0, "keep_alive_time_seconds": 0, "launch_commands": ["string"], "resource_size_request": "SMALL", @@ -604,7 +668,11 @@ async def test_raw_response_update(self, async_client: AsyncRunloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] @@ -626,7 +694,11 @@ async def test_streaming_response_update(self, async_client: AsyncRunloop) -> No "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] @@ -651,7 +723,11 @@ async def test_path_params_update(self, async_client: AsyncRunloop) -> None: "scoring_function_parameters": [ { "name": "name", - "type": "type", + "scoring_function": { + "pattern": "pattern", + "search_directory": "search_directory", + "type": "ast_grep_scorer", + }, "weight": 0, } ] diff --git a/tests/test_models.py b/tests/test_models.py index 78b2d1141..b65dd474e 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -854,3 +854,35 @@ class Model(BaseModel): m = construct_type(value={"cls": "foo"}, type_=Model) assert isinstance(m, Model) assert isinstance(m.cls, str) + + +def test_discriminated_union_case() -> None: + class A(BaseModel): + type: Literal["a"] + + data: bool + + class B(BaseModel): + type: Literal["b"] + + data: List[Union[A, object]] + + class ModelA(BaseModel): + type: Literal["modelA"] + + data: int + + class ModelB(BaseModel): + type: Literal["modelB"] + + required: str + + data: Union[A, B] + + # when constructing ModelA | ModelB, value data doesn't match ModelB exactly - missing `required` + m = construct_type( + value={"type": "modelB", "data": {"type": "a", "data": True}}, + type_=cast(Any, Annotated[Union[ModelA, ModelB], PropertyInfo(discriminator="type")]), + ) + + assert isinstance(m, ModelB)