From e55b71f493d1b8a568b0c2334b088e15232b9aea Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 3 Aug 2026 13:35:54 +0000 Subject: [PATCH 1/2] chore(closes OPEN-11851): expose update project endpoint --- .stats.yml | 6 +- api.md | 3 +- src/openlayer/resources/projects/projects.py | 177 +++++++++++++++++- src/openlayer/types/__init__.py | 2 + .../inference_pipeline_retrieve_response.py | 15 ++ .../inference_pipeline_update_response.py | 15 ++ src/openlayer/types/project_create_params.py | 16 ++ .../types/project_create_response.py | 17 +- src/openlayer/types/project_list_response.py | 15 ++ src/openlayer/types/project_update_params.py | 34 ++++ .../types/project_update_response.py | 109 +++++++++++ .../inference_pipeline_create_params.py | 15 ++ .../inference_pipeline_create_response.py | 15 ++ .../inference_pipeline_list_response.py | 15 ++ .../projects/test_inference_pipelines.py | 8 + tests/api_resources/test_projects.py | 116 +++++++++++- 16 files changed, 570 insertions(+), 8 deletions(-) create mode 100644 src/openlayer/types/project_update_params.py create mode 100644 src/openlayer/types/project_update_response.py diff --git a/.stats.yml b/.stats.yml index 0deea569..60080a09 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,3 +1,3 @@ -configured_endpoints: 31 -openapi_spec_hash: a574ef9082e992c25120554886a9ab7a -config_hash: 2d4f9621ceae4bb25977853a964a0e54 +configured_endpoints: 32 +openapi_spec_hash: 72e2dd8871904fe6c130d1c81b033d5a +config_hash: f75dd97d47c446f8fdc8bcb36f445eea diff --git a/api.md b/api.md index 40934640..08062d22 100644 --- a/api.md +++ b/api.md @@ -3,12 +3,13 @@ Types: ```python -from openlayer.types import ProjectCreateResponse, ProjectListResponse +from openlayer.types import ProjectCreateResponse, ProjectUpdateResponse, ProjectListResponse ``` Methods: - client.projects.create(\*\*params) -> ProjectCreateResponse +- client.projects.update(project_id, \*\*params) -> ProjectUpdateResponse - client.projects.list(\*\*params) -> ProjectListResponse - client.projects.delete(project_id) -> None diff --git a/src/openlayer/resources/projects/projects.py b/src/openlayer/resources/projects/projects.py index 83ab2d8f..c954b7e9 100644 --- a/src/openlayer/resources/projects/projects.py +++ b/src/openlayer/resources/projects/projects.py @@ -15,7 +15,7 @@ TestsResourceWithStreamingResponse, AsyncTestsResourceWithStreamingResponse, ) -from ...types import project_list_params, project_create_params +from ...types import project_list_params, project_create_params, project_update_params from .commits import ( CommitsResource, AsyncCommitsResource, @@ -24,7 +24,7 @@ CommitsResourceWithStreamingResponse, AsyncCommitsResourceWithStreamingResponse, ) -from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -45,6 +45,7 @@ ) from ...types.project_list_response import ProjectListResponse from ...types.project_create_response import ProjectCreateResponse +from ...types.project_update_response import ProjectUpdateResponse __all__ = ["ProjectsResource", "AsyncProjectsResource"] @@ -86,7 +87,11 @@ def create( *, name: str, task_type: Literal["llm-base", "tabular-classification", "tabular-regression", "text-classification"], + data_retention_days: Optional[int] | Omit = omit, description: Optional[str] | Omit = omit, + model_developer: Optional[str] | Omit = omit, + model_types: Optional[SequenceNotStr[str]] | Omit = omit, + purpose: Optional[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, @@ -102,8 +107,17 @@ def create( task_type: The task type of the project. + data_retention_days: Number of days to retain monitoring data for this project. Null means data is + retained indefinitely. + description: The project description. + model_developer: Who developed the model used in this project. + + model_types: The kinds of model used in this project. + + purpose: What the system in this project is intended to do. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -118,7 +132,11 @@ def create( { "name": name, "task_type": task_type, + "data_retention_days": data_retention_days, "description": description, + "model_developer": model_developer, + "model_types": model_types, + "purpose": purpose, }, project_create_params.ProjectCreateParams, ), @@ -128,6 +146,69 @@ def create( cast_to=ProjectCreateResponse, ) + def update( + self, + project_id: str, + *, + data_retention_days: Optional[int] | Omit = omit, + description: Optional[str] | Omit = omit, + model_developer: Optional[str] | Omit = omit, + model_types: Optional[SequenceNotStr[str]] | Omit = omit, + name: str | Omit = omit, + purpose: Optional[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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectUpdateResponse: + """ + Update a project's metadata. + + Args: + data_retention_days: Number of days to retain monitoring data for this project. Null means data is + retained indefinitely. + + description: The project description. + + model_developer: Who developed the model used in this project. + + model_types: The kinds of model used in this project. + + name: The project name. + + purpose: What the system in this project is intended to do. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return self._patch( + path_template("/projects/{project_id}", project_id=project_id), + body=maybe_transform( + { + "data_retention_days": data_retention_days, + "description": description, + "model_developer": model_developer, + "model_types": model_types, + "name": name, + "purpose": purpose, + }, + project_update_params.ProjectUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProjectUpdateResponse, + ) + def list( self, *, @@ -255,7 +336,11 @@ async def create( *, name: str, task_type: Literal["llm-base", "tabular-classification", "tabular-regression", "text-classification"], + data_retention_days: Optional[int] | Omit = omit, description: Optional[str] | Omit = omit, + model_developer: Optional[str] | Omit = omit, + model_types: Optional[SequenceNotStr[str]] | Omit = omit, + purpose: Optional[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, @@ -271,8 +356,17 @@ async def create( task_type: The task type of the project. + data_retention_days: Number of days to retain monitoring data for this project. Null means data is + retained indefinitely. + description: The project description. + model_developer: Who developed the model used in this project. + + model_types: The kinds of model used in this project. + + purpose: What the system in this project is intended to do. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -287,7 +381,11 @@ async def create( { "name": name, "task_type": task_type, + "data_retention_days": data_retention_days, "description": description, + "model_developer": model_developer, + "model_types": model_types, + "purpose": purpose, }, project_create_params.ProjectCreateParams, ), @@ -297,6 +395,69 @@ async def create( cast_to=ProjectCreateResponse, ) + async def update( + self, + project_id: str, + *, + data_retention_days: Optional[int] | Omit = omit, + description: Optional[str] | Omit = omit, + model_developer: Optional[str] | Omit = omit, + model_types: Optional[SequenceNotStr[str]] | Omit = omit, + name: str | Omit = omit, + purpose: Optional[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, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ProjectUpdateResponse: + """ + Update a project's metadata. + + Args: + data_retention_days: Number of days to retain monitoring data for this project. Null means data is + retained indefinitely. + + description: The project description. + + model_developer: Who developed the model used in this project. + + model_types: The kinds of model used in this project. + + name: The project name. + + purpose: What the system in this project is intended to do. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not project_id: + raise ValueError(f"Expected a non-empty value for `project_id` but received {project_id!r}") + return await self._patch( + path_template("/projects/{project_id}", project_id=project_id), + body=await async_maybe_transform( + { + "data_retention_days": data_retention_days, + "description": description, + "model_developer": model_developer, + "model_types": model_types, + "name": name, + "purpose": purpose, + }, + project_update_params.ProjectUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ProjectUpdateResponse, + ) + async def list( self, *, @@ -394,6 +555,9 @@ def __init__(self, projects: ProjectsResource) -> None: self.create = to_raw_response_wrapper( projects.create, ) + self.update = to_raw_response_wrapper( + projects.update, + ) self.list = to_raw_response_wrapper( projects.list, ) @@ -421,6 +585,9 @@ def __init__(self, projects: AsyncProjectsResource) -> None: self.create = async_to_raw_response_wrapper( projects.create, ) + self.update = async_to_raw_response_wrapper( + projects.update, + ) self.list = async_to_raw_response_wrapper( projects.list, ) @@ -448,6 +615,9 @@ def __init__(self, projects: ProjectsResource) -> None: self.create = to_streamed_response_wrapper( projects.create, ) + self.update = to_streamed_response_wrapper( + projects.update, + ) self.list = to_streamed_response_wrapper( projects.list, ) @@ -475,6 +645,9 @@ def __init__(self, projects: AsyncProjectsResource) -> None: self.create = async_to_streamed_response_wrapper( projects.create, ) + self.update = async_to_streamed_response_wrapper( + projects.update, + ) self.list = async_to_streamed_response_wrapper( projects.list, ) diff --git a/src/openlayer/types/__init__.py b/src/openlayer/types/__init__.py index a11cd774..b5752698 100644 --- a/src/openlayer/types/__init__.py +++ b/src/openlayer/types/__init__.py @@ -6,8 +6,10 @@ from .test_evaluate_params import TestEvaluateParams as TestEvaluateParams from .project_create_params import ProjectCreateParams as ProjectCreateParams from .project_list_response import ProjectListResponse as ProjectListResponse +from .project_update_params import ProjectUpdateParams as ProjectUpdateParams from .test_evaluate_response import TestEvaluateResponse as TestEvaluateResponse from .project_create_response import ProjectCreateResponse as ProjectCreateResponse +from .project_update_response import ProjectUpdateResponse as ProjectUpdateResponse from .workspace_update_params import WorkspaceUpdateParams as WorkspaceUpdateParams from .commit_retrieve_response import CommitRetrieveResponse as CommitRetrieveResponse from .test_list_results_params import TestListResultsParams as TestListResultsParams diff --git a/src/openlayer/types/inference_pipeline_retrieve_response.py b/src/openlayer/types/inference_pipeline_retrieve_response.py index 11dfd5c5..d91c59b9 100644 --- a/src/openlayer/types/inference_pipeline_retrieve_response.py +++ b/src/openlayer/types/inference_pipeline_retrieve_response.py @@ -273,11 +273,26 @@ class Project(BaseModel): workspace_id: Optional[str] = FieldInfo(alias="workspaceId", default=None) """The workspace id.""" + data_retention_days: Optional[int] = FieldInfo(alias="dataRetentionDays", default=None) + """Number of days to retain monitoring data for this project. + + Null means data is retained indefinitely. + """ + description: Optional[str] = None """The project description.""" git_repo: Optional[ProjectGitRepo] = FieldInfo(alias="gitRepo", default=None) + api_model_developer: Optional[str] = FieldInfo(alias="modelDeveloper", default=None) + """Who developed the model used in this project.""" + + api_model_types: Optional[List[str]] = FieldInfo(alias="modelTypes", default=None) + """The kinds of model used in this project.""" + + purpose: Optional[str] = None + """What the system in this project is intended to do.""" + class WorkspaceMonthlyUsage(BaseModel): execution_time_ms: Optional[int] = FieldInfo(alias="executionTimeMs", default=None) diff --git a/src/openlayer/types/inference_pipeline_update_response.py b/src/openlayer/types/inference_pipeline_update_response.py index fa6235e0..49c10a6e 100644 --- a/src/openlayer/types/inference_pipeline_update_response.py +++ b/src/openlayer/types/inference_pipeline_update_response.py @@ -273,11 +273,26 @@ class Project(BaseModel): workspace_id: Optional[str] = FieldInfo(alias="workspaceId", default=None) """The workspace id.""" + data_retention_days: Optional[int] = FieldInfo(alias="dataRetentionDays", default=None) + """Number of days to retain monitoring data for this project. + + Null means data is retained indefinitely. + """ + description: Optional[str] = None """The project description.""" git_repo: Optional[ProjectGitRepo] = FieldInfo(alias="gitRepo", default=None) + api_model_developer: Optional[str] = FieldInfo(alias="modelDeveloper", default=None) + """Who developed the model used in this project.""" + + api_model_types: Optional[List[str]] = FieldInfo(alias="modelTypes", default=None) + """The kinds of model used in this project.""" + + purpose: Optional[str] = None + """What the system in this project is intended to do.""" + class WorkspaceMonthlyUsage(BaseModel): execution_time_ms: Optional[int] = FieldInfo(alias="executionTimeMs", default=None) diff --git a/src/openlayer/types/project_create_params.py b/src/openlayer/types/project_create_params.py index ef11180f..797db4f7 100644 --- a/src/openlayer/types/project_create_params.py +++ b/src/openlayer/types/project_create_params.py @@ -5,6 +5,7 @@ from typing import Optional from typing_extensions import Literal, Required, Annotated, TypedDict +from .._types import SequenceNotStr from .._utils import PropertyInfo __all__ = ["ProjectCreateParams"] @@ -22,5 +23,20 @@ class ProjectCreateParams(TypedDict, total=False): ] """The task type of the project.""" + data_retention_days: Annotated[Optional[int], PropertyInfo(alias="dataRetentionDays")] + """Number of days to retain monitoring data for this project. + + Null means data is retained indefinitely. + """ + description: Optional[str] """The project description.""" + + model_developer: Annotated[Optional[str], PropertyInfo(alias="modelDeveloper")] + """Who developed the model used in this project.""" + + model_types: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="modelTypes")] + """The kinds of model used in this project.""" + + purpose: Optional[str] + """What the system in this project is intended to do.""" diff --git a/src/openlayer/types/project_create_response.py b/src/openlayer/types/project_create_response.py index aba9fa5c..ee049acf 100644 --- a/src/openlayer/types/project_create_response.py +++ b/src/openlayer/types/project_create_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import List, Optional from datetime import datetime from typing_extensions import Literal @@ -88,7 +88,22 @@ class ProjectCreateResponse(BaseModel): workspace_id: Optional[str] = FieldInfo(alias="workspaceId", default=None) """The workspace id.""" + data_retention_days: Optional[int] = FieldInfo(alias="dataRetentionDays", default=None) + """Number of days to retain monitoring data for this project. + + Null means data is retained indefinitely. + """ + description: Optional[str] = None """The project description.""" git_repo: Optional[GitRepo] = FieldInfo(alias="gitRepo", default=None) + + api_model_developer: Optional[str] = FieldInfo(alias="modelDeveloper", default=None) + """Who developed the model used in this project.""" + + api_model_types: Optional[List[str]] = FieldInfo(alias="modelTypes", default=None) + """The kinds of model used in this project.""" + + purpose: Optional[str] = None + """What the system in this project is intended to do.""" diff --git a/src/openlayer/types/project_list_response.py b/src/openlayer/types/project_list_response.py index 5c07e87b..1461ddae 100644 --- a/src/openlayer/types/project_list_response.py +++ b/src/openlayer/types/project_list_response.py @@ -88,11 +88,26 @@ class Item(BaseModel): workspace_id: Optional[str] = FieldInfo(alias="workspaceId", default=None) """The workspace id.""" + data_retention_days: Optional[int] = FieldInfo(alias="dataRetentionDays", default=None) + """Number of days to retain monitoring data for this project. + + Null means data is retained indefinitely. + """ + description: Optional[str] = None """The project description.""" git_repo: Optional[ItemGitRepo] = FieldInfo(alias="gitRepo", default=None) + api_model_developer: Optional[str] = FieldInfo(alias="modelDeveloper", default=None) + """Who developed the model used in this project.""" + + api_model_types: Optional[List[str]] = FieldInfo(alias="modelTypes", default=None) + """The kinds of model used in this project.""" + + purpose: Optional[str] = None + """What the system in this project is intended to do.""" + class ProjectListResponse(BaseModel): items: List[Item] diff --git a/src/openlayer/types/project_update_params.py b/src/openlayer/types/project_update_params.py new file mode 100644 index 00000000..02e1090f --- /dev/null +++ b/src/openlayer/types/project_update_params.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Annotated, TypedDict + +from .._types import SequenceNotStr +from .._utils import PropertyInfo + +__all__ = ["ProjectUpdateParams"] + + +class ProjectUpdateParams(TypedDict, total=False): + data_retention_days: Annotated[Optional[int], PropertyInfo(alias="dataRetentionDays")] + """Number of days to retain monitoring data for this project. + + Null means data is retained indefinitely. + """ + + description: Optional[str] + """The project description.""" + + model_developer: Annotated[Optional[str], PropertyInfo(alias="modelDeveloper")] + """Who developed the model used in this project.""" + + model_types: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="modelTypes")] + """The kinds of model used in this project.""" + + name: str + """The project name.""" + + purpose: Optional[str] + """What the system in this project is intended to do.""" diff --git a/src/openlayer/types/project_update_response.py b/src/openlayer/types/project_update_response.py new file mode 100644 index 00000000..26d804e3 --- /dev/null +++ b/src/openlayer/types/project_update_response.py @@ -0,0 +1,109 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["ProjectUpdateResponse", "Links", "GitRepo"] + + +class Links(BaseModel): + """Links to the project.""" + + app: str + + +class GitRepo(BaseModel): + id: str + + date_connected: datetime = FieldInfo(alias="dateConnected") + + date_updated: datetime = FieldInfo(alias="dateUpdated") + + git_account_id: str = FieldInfo(alias="gitAccountId") + + git_id: int = FieldInfo(alias="gitId") + + name: str + + private: bool + + project_id: str = FieldInfo(alias="projectId") + + slug: str + + url: str + + branch: Optional[str] = None + + root_dir: Optional[str] = FieldInfo(alias="rootDir", default=None) + + +class ProjectUpdateResponse(BaseModel): + id: str + """The project id.""" + + creator_id: Optional[str] = FieldInfo(alias="creatorId", default=None) + """The project creator id.""" + + date_created: datetime = FieldInfo(alias="dateCreated") + """The project creation date.""" + + date_updated: datetime = FieldInfo(alias="dateUpdated") + """The project last updated date.""" + + development_goal_count: int = FieldInfo(alias="developmentGoalCount") + """The number of tests in the development mode of the project.""" + + goal_count: int = FieldInfo(alias="goalCount") + """The total number of tests in the project.""" + + inference_pipeline_count: int = FieldInfo(alias="inferencePipelineCount") + """The number of inference pipelines in the project.""" + + links: Links + """Links to the project.""" + + monitoring_goal_count: int = FieldInfo(alias="monitoringGoalCount") + """The number of tests in the monitoring mode of the project.""" + + name: str + """The project name.""" + + source: Optional[Literal["web", "api", "null"]] = None + """The source of the project.""" + + task_type: Literal["llm-base", "tabular-classification", "tabular-regression", "text-classification"] = FieldInfo( + alias="taskType" + ) + """The task type of the project.""" + + version_count: int = FieldInfo(alias="versionCount") + """The number of versions (commits) in the project.""" + + workspace_id: Optional[str] = FieldInfo(alias="workspaceId", default=None) + """The workspace id.""" + + data_retention_days: Optional[int] = FieldInfo(alias="dataRetentionDays", default=None) + """Number of days to retain monitoring data for this project. + + Null means data is retained indefinitely. + """ + + description: Optional[str] = None + """The project description.""" + + git_repo: Optional[GitRepo] = FieldInfo(alias="gitRepo", default=None) + + api_model_developer: Optional[str] = FieldInfo(alias="modelDeveloper", default=None) + """Who developed the model used in this project.""" + + api_model_types: Optional[List[str]] = FieldInfo(alias="modelTypes", default=None) + """The kinds of model used in this project.""" + + purpose: Optional[str] = None + """What the system in this project is intended to do.""" diff --git a/src/openlayer/types/projects/inference_pipeline_create_params.py b/src/openlayer/types/projects/inference_pipeline_create_params.py index 88230a4c..b41a4353 100644 --- a/src/openlayer/types/projects/inference_pipeline_create_params.py +++ b/src/openlayer/types/projects/inference_pipeline_create_params.py @@ -258,9 +258,24 @@ class Project(TypedDict, total=False): ] """The task type of the project.""" + data_retention_days: Annotated[Optional[int], PropertyInfo(alias="dataRetentionDays")] + """Number of days to retain monitoring data for this project. + + Null means data is retained indefinitely. + """ + description: Optional[str] """The project description.""" + model_developer: Annotated[Optional[str], PropertyInfo(alias="modelDeveloper")] + """Who developed the model used in this project.""" + + model_types: Annotated[Optional[SequenceNotStr[str]], PropertyInfo(alias="modelTypes")] + """The kinds of model used in this project.""" + + purpose: Optional[str] + """What the system in this project is intended to do.""" + class Workspace(TypedDict, total=False): name: Required[str] diff --git a/src/openlayer/types/projects/inference_pipeline_create_response.py b/src/openlayer/types/projects/inference_pipeline_create_response.py index 17b2b6fa..55ebce2c 100644 --- a/src/openlayer/types/projects/inference_pipeline_create_response.py +++ b/src/openlayer/types/projects/inference_pipeline_create_response.py @@ -273,11 +273,26 @@ class Project(BaseModel): workspace_id: Optional[str] = FieldInfo(alias="workspaceId", default=None) """The workspace id.""" + data_retention_days: Optional[int] = FieldInfo(alias="dataRetentionDays", default=None) + """Number of days to retain monitoring data for this project. + + Null means data is retained indefinitely. + """ + description: Optional[str] = None """The project description.""" git_repo: Optional[ProjectGitRepo] = FieldInfo(alias="gitRepo", default=None) + api_model_developer: Optional[str] = FieldInfo(alias="modelDeveloper", default=None) + """Who developed the model used in this project.""" + + api_model_types: Optional[List[str]] = FieldInfo(alias="modelTypes", default=None) + """The kinds of model used in this project.""" + + purpose: Optional[str] = None + """What the system in this project is intended to do.""" + class WorkspaceMonthlyUsage(BaseModel): execution_time_ms: Optional[int] = FieldInfo(alias="executionTimeMs", default=None) diff --git a/src/openlayer/types/projects/inference_pipeline_list_response.py b/src/openlayer/types/projects/inference_pipeline_list_response.py index c47cb0ce..96e12347 100644 --- a/src/openlayer/types/projects/inference_pipeline_list_response.py +++ b/src/openlayer/types/projects/inference_pipeline_list_response.py @@ -274,11 +274,26 @@ class ItemProject(BaseModel): workspace_id: Optional[str] = FieldInfo(alias="workspaceId", default=None) """The workspace id.""" + data_retention_days: Optional[int] = FieldInfo(alias="dataRetentionDays", default=None) + """Number of days to retain monitoring data for this project. + + Null means data is retained indefinitely. + """ + description: Optional[str] = None """The project description.""" git_repo: Optional[ItemProjectGitRepo] = FieldInfo(alias="gitRepo", default=None) + api_model_developer: Optional[str] = FieldInfo(alias="modelDeveloper", default=None) + """Who developed the model used in this project.""" + + api_model_types: Optional[List[str]] = FieldInfo(alias="modelTypes", default=None) + """The kinds of model used in this project.""" + + purpose: Optional[str] = None + """What the system in this project is intended to do.""" + class ItemWorkspaceMonthlyUsage(BaseModel): execution_time_ms: Optional[int] = FieldInfo(alias="executionTimeMs", default=None) diff --git a/tests/api_resources/projects/test_inference_pipelines.py b/tests/api_resources/projects/test_inference_pipelines.py index eb112725..31c772e5 100644 --- a/tests/api_resources/projects/test_inference_pipelines.py +++ b/tests/api_resources/projects/test_inference_pipelines.py @@ -53,7 +53,11 @@ def test_method_create_with_all_params(self, client: Openlayer) -> None: project={ "name": "My Project", "task_type": "llm-base", + "data_retention_days": 30, "description": "My project description.", + "model_developer": "Acme AI", + "model_types": ["llm"], + "purpose": "Answer customer billing questions.", }, workspace={ "name": "Openlayer", @@ -189,7 +193,11 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenlayer) project={ "name": "My Project", "task_type": "llm-base", + "data_retention_days": 30, "description": "My project description.", + "model_developer": "Acme AI", + "model_types": ["llm"], + "purpose": "Answer customer billing questions.", }, workspace={ "name": "Openlayer", diff --git a/tests/api_resources/test_projects.py b/tests/api_resources/test_projects.py index 98edf4e1..efb2a2a6 100644 --- a/tests/api_resources/test_projects.py +++ b/tests/api_resources/test_projects.py @@ -9,7 +9,11 @@ from openlayer import Openlayer, AsyncOpenlayer from tests.utils import assert_matches_type -from openlayer.types import ProjectListResponse, ProjectCreateResponse +from openlayer.types import ( + ProjectListResponse, + ProjectCreateResponse, + ProjectUpdateResponse, +) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") @@ -30,7 +34,11 @@ def test_method_create_with_all_params(self, client: Openlayer) -> None: project = client.projects.create( name="My Project", task_type="llm-base", + data_retention_days=30, description="My project description.", + model_developer="Acme AI", + model_types=["llm"], + purpose="Answer customer billing questions.", ) assert_matches_type(ProjectCreateResponse, project, path=["response"]) @@ -60,6 +68,57 @@ def test_streaming_response_create(self, client: Openlayer) -> None: assert cast(Any, response.is_closed) is True + @parametrize + def test_method_update(self, client: Openlayer) -> None: + project = client.projects.update( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + @parametrize + def test_method_update_with_all_params(self, client: Openlayer) -> None: + project = client.projects.update( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + data_retention_days=30, + description="My project description.", + model_developer="Acme AI", + model_types=["llm"], + name="My Project", + purpose="Answer customer billing questions.", + ) + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + @parametrize + def test_raw_response_update(self, client: Openlayer) -> None: + response = client.projects.with_raw_response.update( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = response.parse() + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + @parametrize + def test_streaming_response_update(self, client: Openlayer) -> None: + with client.projects.with_streaming_response.update( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = response.parse() + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_update(self, client: Openlayer) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.projects.with_raw_response.update( + project_id="", + ) + @parametrize def test_method_list(self, client: Openlayer) -> None: project = client.projects.list() @@ -152,7 +211,11 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenlayer) project = await async_client.projects.create( name="My Project", task_type="llm-base", + data_retention_days=30, description="My project description.", + model_developer="Acme AI", + model_types=["llm"], + purpose="Answer customer billing questions.", ) assert_matches_type(ProjectCreateResponse, project, path=["response"]) @@ -182,6 +245,57 @@ async def test_streaming_response_create(self, async_client: AsyncOpenlayer) -> assert cast(Any, response.is_closed) is True + @parametrize + async def test_method_update(self, async_client: AsyncOpenlayer) -> None: + project = await async_client.projects.update( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncOpenlayer) -> None: + project = await async_client.projects.update( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + data_retention_days=30, + description="My project description.", + model_developer="Acme AI", + model_types=["llm"], + name="My Project", + purpose="Answer customer billing questions.", + ) + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + @parametrize + async def test_raw_response_update(self, async_client: AsyncOpenlayer) -> None: + response = await async_client.projects.with_raw_response.update( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + project = await response.parse() + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + @parametrize + async def test_streaming_response_update(self, async_client: AsyncOpenlayer) -> None: + async with async_client.projects.with_streaming_response.update( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + project = await response.parse() + assert_matches_type(ProjectUpdateResponse, project, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_update(self, async_client: AsyncOpenlayer) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.projects.with_raw_response.update( + project_id="", + ) + @parametrize async def test_method_list(self, async_client: AsyncOpenlayer) -> None: project = await async_client.projects.list() From 3aaddf9451f3aa8465357856b10037a416c8145a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 3 Aug 2026 13:36:21 +0000 Subject: [PATCH 2/2] release: 0.31.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ pyproject.toml | 2 +- src/openlayer/_version.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f81bf992..8305d4ab 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.31.0" + ".": "0.31.1" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b4f3764..0e65d055 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## 0.31.1 (2026-08-03) + +Full Changelog: [v0.31.0...v0.31.1](https://github.com/openlayer-ai/openlayer-python/compare/v0.31.0...v0.31.1) + +### Chores + +* **closes OPEN-11851:** expose update project endpoint ([e55b71f](https://github.com/openlayer-ai/openlayer-python/commit/e55b71f493d1b8a568b0c2334b088e15232b9aea)) + ## 0.31.0 (2026-07-29) Full Changelog: [v0.30.1...v0.31.0](https://github.com/openlayer-ai/openlayer-python/compare/v0.30.1...v0.31.0) diff --git a/pyproject.toml b/pyproject.toml index a780a24c..f6a79931 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openlayer" -version = "0.31.0" +version = "0.31.1" description = "The official Python library for the openlayer API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openlayer/_version.py b/src/openlayer/_version.py index a165129a..7cab38cb 100644 --- a/src/openlayer/_version.py +++ b/src/openlayer/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "openlayer" -__version__ = "0.31.0" # x-release-please-version +__version__ = "0.31.1" # x-release-please-version