From f9c02bfd25604f82b0663acdd9ef3a7a57270c59 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 21 Apr 2025 13:11:52 +0000 Subject: [PATCH 1/2] feat(api): add test creation endpoint --- .stats.yml | 4 +- api.md | 12 + src/openlayer/resources/projects/__init__.py | 14 + src/openlayer/resources/projects/projects.py | 32 ++ src/openlayer/resources/projects/tests.py | 288 ++++++++++++++++++ src/openlayer/types/projects/__init__.py | 2 + .../types/projects/test_create_params.py | 82 +++++ .../types/projects/test_create_response.py | 109 +++++++ tests/api_resources/projects/test_tests.py | 206 +++++++++++++ 9 files changed, 747 insertions(+), 2 deletions(-) create mode 100644 src/openlayer/resources/projects/tests.py create mode 100644 src/openlayer/types/projects/test_create_params.py create mode 100644 src/openlayer/types/projects/test_create_response.py create mode 100644 tests/api_resources/projects/test_tests.py diff --git a/.stats.yml b/.stats.yml index 11f2aabc..81ceaeb5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,3 +1,3 @@ -configured_endpoints: 15 +configured_endpoints: 16 openapi_spec_hash: 7dd38774b534c352620bca63efa85b19 -config_hash: 21fb9730d1cdc9e3fd38724c4774b894 +config_hash: 0383360784fc87d799bad2be203142b5 diff --git a/api.md b/api.md index 6f719c19..950966ef 100644 --- a/api.md +++ b/api.md @@ -37,6 +37,18 @@ Methods: - client.projects.inference_pipelines.create(project_id, \*\*params) -> InferencePipelineCreateResponse - client.projects.inference_pipelines.list(project_id, \*\*params) -> InferencePipelineListResponse +## Tests + +Types: + +```python +from openlayer.types.projects import TestCreateResponse +``` + +Methods: + +- client.projects.tests.create(project_id, \*\*params) -> TestCreateResponse + # Commits Types: diff --git a/src/openlayer/resources/projects/__init__.py b/src/openlayer/resources/projects/__init__.py index 47503c6d..3cbde645 100644 --- a/src/openlayer/resources/projects/__init__.py +++ b/src/openlayer/resources/projects/__init__.py @@ -1,5 +1,13 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from .tests import ( + TestsResource, + AsyncTestsResource, + TestsResourceWithRawResponse, + AsyncTestsResourceWithRawResponse, + TestsResourceWithStreamingResponse, + AsyncTestsResourceWithStreamingResponse, +) from .commits import ( CommitsResource, AsyncCommitsResource, @@ -38,6 +46,12 @@ "AsyncInferencePipelinesResourceWithRawResponse", "InferencePipelinesResourceWithStreamingResponse", "AsyncInferencePipelinesResourceWithStreamingResponse", + "TestsResource", + "AsyncTestsResource", + "TestsResourceWithRawResponse", + "AsyncTestsResourceWithRawResponse", + "TestsResourceWithStreamingResponse", + "AsyncTestsResourceWithStreamingResponse", "ProjectsResource", "AsyncProjectsResource", "ProjectsResourceWithRawResponse", diff --git a/src/openlayer/resources/projects/projects.py b/src/openlayer/resources/projects/projects.py index de402a7c..7ab00ce1 100644 --- a/src/openlayer/resources/projects/projects.py +++ b/src/openlayer/resources/projects/projects.py @@ -7,6 +7,14 @@ import httpx +from .tests import ( + TestsResource, + AsyncTestsResource, + TestsResourceWithRawResponse, + AsyncTestsResourceWithRawResponse, + TestsResourceWithStreamingResponse, + AsyncTestsResourceWithStreamingResponse, +) from ...types import project_list_params, project_create_params from .commits import ( CommitsResource, @@ -53,6 +61,10 @@ def commits(self) -> CommitsResource: def inference_pipelines(self) -> InferencePipelinesResource: return InferencePipelinesResource(self._client) + @cached_property + def tests(self) -> TestsResource: + return TestsResource(self._client) + @cached_property def with_raw_response(self) -> ProjectsResourceWithRawResponse: """ @@ -184,6 +196,10 @@ def commits(self) -> AsyncCommitsResource: def inference_pipelines(self) -> AsyncInferencePipelinesResource: return AsyncInferencePipelinesResource(self._client) + @cached_property + def tests(self) -> AsyncTestsResource: + return AsyncTestsResource(self._client) + @cached_property def with_raw_response(self) -> AsyncProjectsResourceWithRawResponse: """ @@ -325,6 +341,10 @@ def commits(self) -> CommitsResourceWithRawResponse: def inference_pipelines(self) -> InferencePipelinesResourceWithRawResponse: return InferencePipelinesResourceWithRawResponse(self._projects.inference_pipelines) + @cached_property + def tests(self) -> TestsResourceWithRawResponse: + return TestsResourceWithRawResponse(self._projects.tests) + class AsyncProjectsResourceWithRawResponse: def __init__(self, projects: AsyncProjectsResource) -> None: @@ -345,6 +365,10 @@ def commits(self) -> AsyncCommitsResourceWithRawResponse: def inference_pipelines(self) -> AsyncInferencePipelinesResourceWithRawResponse: return AsyncInferencePipelinesResourceWithRawResponse(self._projects.inference_pipelines) + @cached_property + def tests(self) -> AsyncTestsResourceWithRawResponse: + return AsyncTestsResourceWithRawResponse(self._projects.tests) + class ProjectsResourceWithStreamingResponse: def __init__(self, projects: ProjectsResource) -> None: @@ -365,6 +389,10 @@ def commits(self) -> CommitsResourceWithStreamingResponse: def inference_pipelines(self) -> InferencePipelinesResourceWithStreamingResponse: return InferencePipelinesResourceWithStreamingResponse(self._projects.inference_pipelines) + @cached_property + def tests(self) -> TestsResourceWithStreamingResponse: + return TestsResourceWithStreamingResponse(self._projects.tests) + class AsyncProjectsResourceWithStreamingResponse: def __init__(self, projects: AsyncProjectsResource) -> None: @@ -384,3 +412,7 @@ def commits(self) -> AsyncCommitsResourceWithStreamingResponse: @cached_property def inference_pipelines(self) -> AsyncInferencePipelinesResourceWithStreamingResponse: return AsyncInferencePipelinesResourceWithStreamingResponse(self._projects.inference_pipelines) + + @cached_property + def tests(self) -> AsyncTestsResourceWithStreamingResponse: + return AsyncTestsResourceWithStreamingResponse(self._projects.tests) diff --git a/src/openlayer/resources/projects/tests.py b/src/openlayer/resources/projects/tests.py new file mode 100644 index 00000000..a07cc645 --- /dev/null +++ b/src/openlayer/resources/projects/tests.py @@ -0,0 +1,288 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional + +import httpx + +from ..._types import NOT_GIVEN, Body, Query, Headers, NotGiven +from ..._utils import ( + maybe_transform, + async_maybe_transform, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.projects import test_create_params +from ...types.projects.test_create_response import TestCreateResponse + +__all__ = ["TestsResource", "AsyncTestsResource"] + + +class TestsResource(SyncAPIResource): + __test__ = False + + @cached_property + def with_raw_response(self) -> TestsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openlayer-ai/openlayer-python#accessing-raw-response-data-eg-headers + """ + return TestsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> TestsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openlayer-ai/openlayer-python#with_streaming_response + """ + return TestsResourceWithStreamingResponse(self) + + def create( + self, + project_id: str, + *, + description: Optional[object], + name: str, + subtype: str, + thresholds: Iterable[test_create_params.Threshold], + type: str, + archived: bool | NotGiven = NOT_GIVEN, + delay_window: Optional[float] | NotGiven = NOT_GIVEN, + evaluation_window: Optional[float] | NotGiven = NOT_GIVEN, + uses_ml_model: bool | NotGiven = NOT_GIVEN, + uses_production_data: bool | NotGiven = NOT_GIVEN, + uses_reference_dataset: bool | NotGiven = NOT_GIVEN, + uses_training_dataset: bool | NotGiven = NOT_GIVEN, + uses_validation_dataset: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> TestCreateResponse: + """ + Create a test. + + Args: + description: The test description. + + name: The test name. + + subtype: The test subtype. + + type: The test type. + + archived: Whether the test is archived. + + delay_window: The delay window in seconds. Only applies to tests that use production data. + + evaluation_window: The evaluation window in seconds. Only applies to tests that use production + data. + + uses_ml_model: Whether the test uses an ML model. + + uses_production_data: Whether the test uses production data (monitoring mode only). + + uses_reference_dataset: Whether the test uses a reference dataset (monitoring mode only). + + uses_training_dataset: Whether the test uses a training dataset. + + uses_validation_dataset: Whether the test uses a validation dataset. + + 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._post( + f"/projects/{project_id}/tests", + body=maybe_transform( + { + "description": description, + "name": name, + "subtype": subtype, + "thresholds": thresholds, + "type": type, + "archived": archived, + "delay_window": delay_window, + "evaluation_window": evaluation_window, + "uses_ml_model": uses_ml_model, + "uses_production_data": uses_production_data, + "uses_reference_dataset": uses_reference_dataset, + "uses_training_dataset": uses_training_dataset, + "uses_validation_dataset": uses_validation_dataset, + }, + test_create_params.TestCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TestCreateResponse, + ) + + +class AsyncTestsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncTestsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/openlayer-ai/openlayer-python#accessing-raw-response-data-eg-headers + """ + return AsyncTestsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncTestsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/openlayer-ai/openlayer-python#with_streaming_response + """ + return AsyncTestsResourceWithStreamingResponse(self) + + async def create( + self, + project_id: str, + *, + description: Optional[object], + name: str, + subtype: str, + thresholds: Iterable[test_create_params.Threshold], + type: str, + archived: bool | NotGiven = NOT_GIVEN, + delay_window: Optional[float] | NotGiven = NOT_GIVEN, + evaluation_window: Optional[float] | NotGiven = NOT_GIVEN, + uses_ml_model: bool | NotGiven = NOT_GIVEN, + uses_production_data: bool | NotGiven = NOT_GIVEN, + uses_reference_dataset: bool | NotGiven = NOT_GIVEN, + uses_training_dataset: bool | NotGiven = NOT_GIVEN, + uses_validation_dataset: bool | NotGiven = NOT_GIVEN, + # 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, + ) -> TestCreateResponse: + """ + Create a test. + + Args: + description: The test description. + + name: The test name. + + subtype: The test subtype. + + type: The test type. + + archived: Whether the test is archived. + + delay_window: The delay window in seconds. Only applies to tests that use production data. + + evaluation_window: The evaluation window in seconds. Only applies to tests that use production + data. + + uses_ml_model: Whether the test uses an ML model. + + uses_production_data: Whether the test uses production data (monitoring mode only). + + uses_reference_dataset: Whether the test uses a reference dataset (monitoring mode only). + + uses_training_dataset: Whether the test uses a training dataset. + + uses_validation_dataset: Whether the test uses a validation dataset. + + 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._post( + f"/projects/{project_id}/tests", + body=await async_maybe_transform( + { + "description": description, + "name": name, + "subtype": subtype, + "thresholds": thresholds, + "type": type, + "archived": archived, + "delay_window": delay_window, + "evaluation_window": evaluation_window, + "uses_ml_model": uses_ml_model, + "uses_production_data": uses_production_data, + "uses_reference_dataset": uses_reference_dataset, + "uses_training_dataset": uses_training_dataset, + "uses_validation_dataset": uses_validation_dataset, + }, + test_create_params.TestCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=TestCreateResponse, + ) + + +class TestsResourceWithRawResponse: + __test__ = False + + def __init__(self, tests: TestsResource) -> None: + self._tests = tests + + self.create = to_raw_response_wrapper( + tests.create, + ) + + +class AsyncTestsResourceWithRawResponse: + def __init__(self, tests: AsyncTestsResource) -> None: + self._tests = tests + + self.create = async_to_raw_response_wrapper( + tests.create, + ) + + +class TestsResourceWithStreamingResponse: + __test__ = False + + def __init__(self, tests: TestsResource) -> None: + self._tests = tests + + self.create = to_streamed_response_wrapper( + tests.create, + ) + + +class AsyncTestsResourceWithStreamingResponse: + def __init__(self, tests: AsyncTestsResource) -> None: + self._tests = tests + + self.create = async_to_streamed_response_wrapper( + tests.create, + ) diff --git a/src/openlayer/types/projects/__init__.py b/src/openlayer/types/projects/__init__.py index d8b9520e..ea357326 100644 --- a/src/openlayer/types/projects/__init__.py +++ b/src/openlayer/types/projects/__init__.py @@ -3,8 +3,10 @@ from __future__ import annotations from .commit_list_params import CommitListParams as CommitListParams +from .test_create_params import TestCreateParams as TestCreateParams from .commit_create_params import CommitCreateParams as CommitCreateParams from .commit_list_response import CommitListResponse as CommitListResponse +from .test_create_response import TestCreateResponse as TestCreateResponse from .commit_create_response import CommitCreateResponse as CommitCreateResponse from .inference_pipeline_list_params import InferencePipelineListParams as InferencePipelineListParams from .inference_pipeline_create_params import InferencePipelineCreateParams as InferencePipelineCreateParams diff --git a/src/openlayer/types/projects/test_create_params.py b/src/openlayer/types/projects/test_create_params.py new file mode 100644 index 00000000..5a0400cc --- /dev/null +++ b/src/openlayer/types/projects/test_create_params.py @@ -0,0 +1,82 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Iterable, Optional +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["TestCreateParams", "Threshold", "ThresholdInsightParameter"] + + +class TestCreateParams(TypedDict, total=False): + description: Required[Optional[object]] + """The test description.""" + + name: Required[str] + """The test name.""" + + subtype: Required[str] + """The test subtype.""" + + thresholds: Required[Iterable[Threshold]] + + type: Required[str] + """The test type.""" + + archived: bool + """Whether the test is archived.""" + + delay_window: Annotated[Optional[float], PropertyInfo(alias="delayWindow")] + """The delay window in seconds. Only applies to tests that use production data.""" + + evaluation_window: Annotated[Optional[float], PropertyInfo(alias="evaluationWindow")] + """The evaluation window in seconds. + + Only applies to tests that use production data. + """ + + uses_ml_model: Annotated[bool, PropertyInfo(alias="usesMlModel")] + """Whether the test uses an ML model.""" + + uses_production_data: Annotated[bool, PropertyInfo(alias="usesProductionData")] + """Whether the test uses production data (monitoring mode only).""" + + uses_reference_dataset: Annotated[bool, PropertyInfo(alias="usesReferenceDataset")] + """Whether the test uses a reference dataset (monitoring mode only).""" + + uses_training_dataset: Annotated[bool, PropertyInfo(alias="usesTrainingDataset")] + """Whether the test uses a training dataset.""" + + uses_validation_dataset: Annotated[bool, PropertyInfo(alias="usesValidationDataset")] + """Whether the test uses a validation dataset.""" + + +class ThresholdInsightParameter(TypedDict, total=False): + name: Required[str] + """The name of the insight filter.""" + + value: Required[object] + + +class Threshold(TypedDict, total=False): + insight_name: Annotated[str, PropertyInfo(alias="insightName")] + """The insight name to be evaluated.""" + + insight_parameters: Annotated[ + Optional[Iterable[ThresholdInsightParameter]], PropertyInfo(alias="insightParameters") + ] + """The insight parameters. Required only for some test subtypes.""" + + measurement: str + """The measurement to be evaluated.""" + + operator: Literal["is", ">", ">=", "<", "<=", "!="] + """The operator to be used for the evaluation.""" + + threshold_mode: Annotated[Literal["automatic", "manual"], PropertyInfo(alias="thresholdMode")] + """Whether to use automatic anomaly detection or manual thresholds""" + + value: Union[float, bool, str, List[str]] + """The value to be compared.""" diff --git a/src/openlayer/types/projects/test_create_response.py b/src/openlayer/types/projects/test_create_response.py new file mode 100644 index 00000000..a9763dd0 --- /dev/null +++ b/src/openlayer/types/projects/test_create_response.py @@ -0,0 +1,109 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["TestCreateResponse", "Threshold", "ThresholdInsightParameter"] + + +class ThresholdInsightParameter(BaseModel): + name: str + """The name of the insight filter.""" + + value: object + + +class Threshold(BaseModel): + insight_name: Optional[str] = FieldInfo(alias="insightName", default=None) + """The insight name to be evaluated.""" + + insight_parameters: Optional[List[ThresholdInsightParameter]] = FieldInfo(alias="insightParameters", default=None) + """The insight parameters. Required only for some test subtypes.""" + + measurement: Optional[str] = None + """The measurement to be evaluated.""" + + operator: Optional[Literal["is", ">", ">=", "<", "<=", "!="]] = None + """The operator to be used for the evaluation.""" + + threshold_mode: Optional[Literal["automatic", "manual"]] = FieldInfo(alias="thresholdMode", default=None) + """Whether to use automatic anomaly detection or manual thresholds""" + + value: Union[float, bool, str, List[str], None] = None + """The value to be compared.""" + + +class TestCreateResponse(BaseModel): + __test__ = False + id: str + """The test id.""" + + comment_count: int = FieldInfo(alias="commentCount") + """The number of comments on the test.""" + + creator_id: Optional[str] = FieldInfo(alias="creatorId", default=None) + """The test creator id.""" + + date_archived: Optional[datetime] = FieldInfo(alias="dateArchived", default=None) + """The date the test was archived.""" + + date_created: datetime = FieldInfo(alias="dateCreated") + """The creation date.""" + + date_updated: datetime = FieldInfo(alias="dateUpdated") + """The last updated date.""" + + description: Optional[object] = None + """The test description.""" + + name: str + """The test name.""" + + number: int + """The test number.""" + + origin_project_version_id: Optional[str] = FieldInfo(alias="originProjectVersionId", default=None) + """The project version (commit) id where the test was created.""" + + subtype: str + """The test subtype.""" + + suggested: bool + """Whether the test is suggested or user-created.""" + + thresholds: List[Threshold] + + type: str + """The test type.""" + + archived: Optional[bool] = None + """Whether the test is archived.""" + + delay_window: Optional[float] = FieldInfo(alias="delayWindow", default=None) + """The delay window in seconds. Only applies to tests that use production data.""" + + evaluation_window: Optional[float] = FieldInfo(alias="evaluationWindow", default=None) + """The evaluation window in seconds. + + Only applies to tests that use production data. + """ + + uses_ml_model: Optional[bool] = FieldInfo(alias="usesMlModel", default=None) + """Whether the test uses an ML model.""" + + uses_production_data: Optional[bool] = FieldInfo(alias="usesProductionData", default=None) + """Whether the test uses production data (monitoring mode only).""" + + uses_reference_dataset: Optional[bool] = FieldInfo(alias="usesReferenceDataset", default=None) + """Whether the test uses a reference dataset (monitoring mode only).""" + + uses_training_dataset: Optional[bool] = FieldInfo(alias="usesTrainingDataset", default=None) + """Whether the test uses a training dataset.""" + + uses_validation_dataset: Optional[bool] = FieldInfo(alias="usesValidationDataset", default=None) + """Whether the test uses a validation dataset.""" diff --git a/tests/api_resources/projects/test_tests.py b/tests/api_resources/projects/test_tests.py new file mode 100644 index 00000000..9e48276d --- /dev/null +++ b/tests/api_resources/projects/test_tests.py @@ -0,0 +1,206 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from openlayer import Openlayer, AsyncOpenlayer +from tests.utils import assert_matches_type +from openlayer.types.projects import TestCreateResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestTests: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_create(self, client: Openlayer) -> None: + test = client.projects.tests.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + description="This test checks for duplicate rows in the dataset.", + name="No duplicate rows", + subtype="duplicateRowCount", + thresholds=[{}], + type="integrity", + ) + assert_matches_type(TestCreateResponse, test, path=["response"]) + + @parametrize + def test_method_create_with_all_params(self, client: Openlayer) -> None: + test = client.projects.tests.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + description="This test checks for duplicate rows in the dataset.", + name="No duplicate rows", + subtype="duplicateRowCount", + thresholds=[ + { + "insight_name": "duplicateRowCount", + "insight_parameters": [ + { + "name": "column_name", + "value": "Age", + } + ], + "measurement": "duplicateRowCount", + "operator": "<=", + "threshold_mode": "automatic", + "value": 0, + } + ], + type="integrity", + archived=False, + delay_window=0, + evaluation_window=3600, + uses_ml_model=False, + uses_production_data=False, + uses_reference_dataset=False, + uses_training_dataset=False, + uses_validation_dataset=True, + ) + assert_matches_type(TestCreateResponse, test, path=["response"]) + + @parametrize + def test_raw_response_create(self, client: Openlayer) -> None: + response = client.projects.tests.with_raw_response.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + description="This test checks for duplicate rows in the dataset.", + name="No duplicate rows", + subtype="duplicateRowCount", + thresholds=[{}], + type="integrity", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + test = response.parse() + assert_matches_type(TestCreateResponse, test, path=["response"]) + + @parametrize + def test_streaming_response_create(self, client: Openlayer) -> None: + with client.projects.tests.with_streaming_response.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + description="This test checks for duplicate rows in the dataset.", + name="No duplicate rows", + subtype="duplicateRowCount", + thresholds=[{}], + type="integrity", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + test = response.parse() + assert_matches_type(TestCreateResponse, test, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_create(self, client: Openlayer) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.projects.tests.with_raw_response.create( + project_id="", + description="This test checks for duplicate rows in the dataset.", + name="No duplicate rows", + subtype="duplicateRowCount", + thresholds=[{}], + type="integrity", + ) + + +class TestAsyncTests: + parametrize = pytest.mark.parametrize("async_client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create(self, async_client: AsyncOpenlayer) -> None: + test = await async_client.projects.tests.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + description="This test checks for duplicate rows in the dataset.", + name="No duplicate rows", + subtype="duplicateRowCount", + thresholds=[{}], + type="integrity", + ) + assert_matches_type(TestCreateResponse, test, path=["response"]) + + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncOpenlayer) -> None: + test = await async_client.projects.tests.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + description="This test checks for duplicate rows in the dataset.", + name="No duplicate rows", + subtype="duplicateRowCount", + thresholds=[ + { + "insight_name": "duplicateRowCount", + "insight_parameters": [ + { + "name": "column_name", + "value": "Age", + } + ], + "measurement": "duplicateRowCount", + "operator": "<=", + "threshold_mode": "automatic", + "value": 0, + } + ], + type="integrity", + archived=False, + delay_window=0, + evaluation_window=3600, + uses_ml_model=False, + uses_production_data=False, + uses_reference_dataset=False, + uses_training_dataset=False, + uses_validation_dataset=True, + ) + assert_matches_type(TestCreateResponse, test, path=["response"]) + + @parametrize + async def test_raw_response_create(self, async_client: AsyncOpenlayer) -> None: + response = await async_client.projects.tests.with_raw_response.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + description="This test checks for duplicate rows in the dataset.", + name="No duplicate rows", + subtype="duplicateRowCount", + thresholds=[{}], + type="integrity", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + test = await response.parse() + assert_matches_type(TestCreateResponse, test, path=["response"]) + + @parametrize + async def test_streaming_response_create(self, async_client: AsyncOpenlayer) -> None: + async with async_client.projects.tests.with_streaming_response.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + description="This test checks for duplicate rows in the dataset.", + name="No duplicate rows", + subtype="duplicateRowCount", + thresholds=[{}], + type="integrity", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + test = await response.parse() + assert_matches_type(TestCreateResponse, test, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_create(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.tests.with_raw_response.create( + project_id="", + description="This test checks for duplicate rows in the dataset.", + name="No duplicate rows", + subtype="duplicateRowCount", + thresholds=[{}], + type="integrity", + ) From 3b9324298e1e69e0f65f1296a37b3191f3bbaf4f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 21 Apr 2025 13:12:22 +0000 Subject: [PATCH 2/2] release: 0.2.0-alpha.56 --- .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 454d8969..0f1fb170 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.2.0-alpha.55" + ".": "0.2.0-alpha.56" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 857a7f1f..e7b41c4b 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.2.0-alpha.56 (2025-04-21) + +Full Changelog: [v0.2.0-alpha.55...v0.2.0-alpha.56](https://github.com/openlayer-ai/openlayer-python/compare/v0.2.0-alpha.55...v0.2.0-alpha.56) + +### Features + +* **api:** add test creation endpoint ([f9c02bf](https://github.com/openlayer-ai/openlayer-python/commit/f9c02bfd25604f82b0663acdd9ef3a7a57270c59)) + ## 0.2.0-alpha.55 (2025-04-19) Full Changelog: [v0.2.0-alpha.54...v0.2.0-alpha.55](https://github.com/openlayer-ai/openlayer-python/compare/v0.2.0-alpha.54...v0.2.0-alpha.55) diff --git a/pyproject.toml b/pyproject.toml index ceebb8c6..9053f1ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openlayer" -version = "0.2.0-alpha.55" +version = "0.2.0-alpha.56" 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 f34e00e9..1a7467ea 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.2.0-alpha.55" # x-release-please-version +__version__ = "0.2.0-alpha.56" # x-release-please-version