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