From 5848aac2eb02a789c20951056a7b802985d8b2ab Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 19 Nov 2025 03:17:41 +0000 Subject: [PATCH 1/3] feat(api): api update --- .stats.yml | 2 +- .../types/projects/query_log_list_by_group_response.py | 6 ++++++ src/codex/types/projects/query_log_list_groups_response.py | 6 ++++++ src/codex/types/projects/query_log_list_response.py | 6 ++++++ src/codex/types/projects/query_log_retrieve_response.py | 6 ++++++ .../projects/remediation_list_resolved_logs_response.py | 6 ++++++ 6 files changed, 31 insertions(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 49a4e3c..36d8a0f 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,3 +1,3 @@ configured_endpoints: 65 -openapi_spec_hash: d273ca5158facc1251efa0a5f9e723c5 +openapi_spec_hash: 9018ebfb2a9e1afa87058b3a4bd41b0b config_hash: cd9208a2204f43e0aa5ab35ac85ef90d diff --git a/src/codex/types/projects/query_log_list_by_group_response.py b/src/codex/types/projects/query_log_list_by_group_response.py index ed1a32d..1a89baa 100644 --- a/src/codex/types/projects/query_log_list_by_group_response.py +++ b/src/codex/types/projects/query_log_list_by_group_response.py @@ -419,6 +419,9 @@ class QueryLogsByGroupQueryLog(BaseModel): applied_expert_answer_id: Optional[str] = None """ID of the expert answer that was applied to the query.""" + applied_expert_review_id: Optional[str] = None + """ID of the expert review that was applied to the query.""" + context: Optional[List[QueryLogsByGroupQueryLogContext]] = None """RAG context used for the query""" @@ -479,6 +482,9 @@ class QueryLogsByGroupQueryLog(BaseModel): expert_review_explanation: Optional[str] = None """Expert explanation when marked as bad""" + expert_review_id: Optional[str] = None + """ID of the expert review that was created for the query.""" + expert_review_status: Optional[Literal["good", "bad"]] = None """Expert review status: 'good' or 'bad'""" diff --git a/src/codex/types/projects/query_log_list_groups_response.py b/src/codex/types/projects/query_log_list_groups_response.py index d20eb8c..fe70223 100644 --- a/src/codex/types/projects/query_log_list_groups_response.py +++ b/src/codex/types/projects/query_log_list_groups_response.py @@ -414,6 +414,9 @@ class QueryLogListGroupsResponse(BaseModel): applied_expert_answer_id: Optional[str] = None """ID of the expert answer that was applied to the query.""" + applied_expert_review_id: Optional[str] = None + """ID of the expert review that was applied to the query.""" + context: Optional[List[Context]] = None """RAG context used for the query""" @@ -474,6 +477,9 @@ class QueryLogListGroupsResponse(BaseModel): expert_review_explanation: Optional[str] = None """Expert explanation when marked as bad""" + expert_review_id: Optional[str] = None + """ID of the expert review that was created for the query.""" + expert_review_status: Optional[Literal["good", "bad"]] = None """Expert review status: 'good' or 'bad'""" diff --git a/src/codex/types/projects/query_log_list_response.py b/src/codex/types/projects/query_log_list_response.py index 9d8d198..dc7768f 100644 --- a/src/codex/types/projects/query_log_list_response.py +++ b/src/codex/types/projects/query_log_list_response.py @@ -402,6 +402,9 @@ class QueryLogListResponse(BaseModel): applied_expert_answer_id: Optional[str] = None """ID of the expert answer that was applied to the query.""" + applied_expert_review_id: Optional[str] = None + """ID of the expert review that was applied to the query.""" + context: Optional[List[Context]] = None """RAG context used for the query""" @@ -462,6 +465,9 @@ class QueryLogListResponse(BaseModel): expert_review_explanation: Optional[str] = None """Expert explanation when marked as bad""" + expert_review_id: Optional[str] = None + """ID of the expert review that was created for the query.""" + expert_review_status: Optional[Literal["good", "bad"]] = None """Expert review status: 'good' or 'bad'""" diff --git a/src/codex/types/projects/query_log_retrieve_response.py b/src/codex/types/projects/query_log_retrieve_response.py index 3943325..db91943 100644 --- a/src/codex/types/projects/query_log_retrieve_response.py +++ b/src/codex/types/projects/query_log_retrieve_response.py @@ -409,6 +409,9 @@ class QueryLogRetrieveResponse(BaseModel): applied_expert_answer_id: Optional[str] = None """ID of the expert answer that was applied to the query.""" + applied_expert_review_id: Optional[str] = None + """ID of the expert review that was applied to the query.""" + context: Optional[List[Context]] = None """RAG context used for the query""" @@ -469,6 +472,9 @@ class QueryLogRetrieveResponse(BaseModel): expert_review_explanation: Optional[str] = None """Expert explanation when marked as bad""" + expert_review_id: Optional[str] = None + """ID of the expert review that was created for the query.""" + expert_review_status: Optional[Literal["good", "bad"]] = None """Expert review status: 'good' or 'bad'""" diff --git a/src/codex/types/projects/remediation_list_resolved_logs_response.py b/src/codex/types/projects/remediation_list_resolved_logs_response.py index e586b14..9f1b77b 100644 --- a/src/codex/types/projects/remediation_list_resolved_logs_response.py +++ b/src/codex/types/projects/remediation_list_resolved_logs_response.py @@ -409,6 +409,9 @@ class QueryLog(BaseModel): applied_expert_answer_id: Optional[str] = None """ID of the expert answer that was applied to the query.""" + applied_expert_review_id: Optional[str] = None + """ID of the expert review that was applied to the query.""" + context: Optional[List[QueryLogContext]] = None """RAG context used for the query""" @@ -469,6 +472,9 @@ class QueryLog(BaseModel): expert_review_explanation: Optional[str] = None """Expert explanation when marked as bad""" + expert_review_id: Optional[str] = None + """ID of the expert review that was created for the query.""" + expert_review_status: Optional[Literal["good", "bad"]] = None """Expert review status: 'good' or 'bad'""" From cda6f911fe678318779d23de9ecc77fb15594fa1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 19 Nov 2025 19:07:15 +0000 Subject: [PATCH 2/3] feat(api): add expert review endpoints --- .stats.yml | 4 +- api.md | 21 + src/codex/pagination.py | 62 ++ .../projects/remediations/__init__.py | 14 + .../projects/remediations/expert_reviews.py | 682 ++++++++++++++++++ .../projects/remediations/remediations.py | 32 + .../types/projects/remediations/__init__.py | 8 + .../expert_review_create_params.py | 21 + .../expert_review_create_response.py | 29 + .../expert_review_delete_params.py | 14 + .../remediations/expert_review_edit_params.py | 16 + .../expert_review_edit_response.py | 29 + .../remediations/expert_review_list_params.py | 41 ++ .../expert_review_list_response.py | 35 + .../expert_review_retrieve_response.py | 35 + .../remediations/test_expert_reviews.py | 631 ++++++++++++++++ 16 files changed, 1672 insertions(+), 2 deletions(-) create mode 100644 src/codex/resources/projects/remediations/expert_reviews.py create mode 100644 src/codex/types/projects/remediations/expert_review_create_params.py create mode 100644 src/codex/types/projects/remediations/expert_review_create_response.py create mode 100644 src/codex/types/projects/remediations/expert_review_delete_params.py create mode 100644 src/codex/types/projects/remediations/expert_review_edit_params.py create mode 100644 src/codex/types/projects/remediations/expert_review_edit_response.py create mode 100644 src/codex/types/projects/remediations/expert_review_list_params.py create mode 100644 src/codex/types/projects/remediations/expert_review_list_response.py create mode 100644 src/codex/types/projects/remediations/expert_review_retrieve_response.py create mode 100644 tests/api_resources/projects/remediations/test_expert_reviews.py diff --git a/.stats.yml b/.stats.yml index 36d8a0f..c021c17 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,3 +1,3 @@ -configured_endpoints: 65 +configured_endpoints: 70 openapi_spec_hash: 9018ebfb2a9e1afa87058b3a4bd41b0b -config_hash: cd9208a2204f43e0aa5ab35ac85ef90d +config_hash: aad16f20fed13ac50211fc1d0e2ea621 diff --git a/api.md b/api.md index 6e8c053..4ee7964 100644 --- a/api.md +++ b/api.md @@ -284,3 +284,24 @@ Methods: - client.projects.remediations.expert_answers.pause(expert_answer_id, \*, project_id) -> ExpertAnswerPauseResponse - client.projects.remediations.expert_answers.publish(expert_answer_id, \*, project_id) -> ExpertAnswerPublishResponse - client.projects.remediations.expert_answers.unpause(expert_answer_id, \*, project_id) -> ExpertAnswerUnpauseResponse + +### ExpertReviews + +Types: + +```python +from codex.types.projects.remediations import ( + ExpertReviewCreateResponse, + ExpertReviewRetrieveResponse, + ExpertReviewListResponse, + ExpertReviewEditResponse, +) +``` + +Methods: + +- client.projects.remediations.expert_reviews.create(project_id, \*\*params) -> ExpertReviewCreateResponse +- client.projects.remediations.expert_reviews.retrieve(expert_review_id, \*, project_id) -> ExpertReviewRetrieveResponse +- client.projects.remediations.expert_reviews.list(project_id, \*\*params) -> SyncOffsetPageExpertReviews[ExpertReviewListResponse] +- client.projects.remediations.expert_reviews.delete(expert_review_id, \*, project_id, \*\*params) -> None +- client.projects.remediations.expert_reviews.edit(expert_review_id, \*, project_id, \*\*params) -> ExpertReviewEditResponse diff --git a/src/codex/pagination.py b/src/codex/pagination.py index e5721eb..d44ce47 100644 --- a/src/codex/pagination.py +++ b/src/codex/pagination.py @@ -24,6 +24,8 @@ "AsyncOffsetPageQueryLogsByGroup", "SyncOffsetPageExpertAnswers", "AsyncOffsetPageExpertAnswers", + "SyncOffsetPageExpertReviews", + "AsyncOffsetPageExpertReviews", ] _BaseModelT = TypeVar("_BaseModelT", bound=BaseModel) @@ -451,3 +453,63 @@ def next_page_info(self) -> Optional[PageInfo]: return PageInfo(params={"offset": current_count}) return None + + +class SyncOffsetPageExpertReviews(BaseSyncPage[_T], BasePage[_T], Generic[_T]): + expert_reviews: List[_T] + total_count: Optional[int] = None + + @override + def _get_page_items(self) -> List[_T]: + expert_reviews = self.expert_reviews + if not expert_reviews: + return [] + return expert_reviews + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + total_count = self.total_count + if total_count is None: + return None + + if current_count < total_count: + return PageInfo(params={"offset": current_count}) + + return None + + +class AsyncOffsetPageExpertReviews(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): + expert_reviews: List[_T] + total_count: Optional[int] = None + + @override + def _get_page_items(self) -> List[_T]: + expert_reviews = self.expert_reviews + if not expert_reviews: + return [] + return expert_reviews + + @override + def next_page_info(self) -> Optional[PageInfo]: + offset = self._options.params.get("offset") or 0 + if not isinstance(offset, int): + raise ValueError(f'Expected "offset" param to be an integer but got {offset}') + + length = len(self._get_page_items()) + current_count = offset + length + + total_count = self.total_count + if total_count is None: + return None + + if current_count < total_count: + return PageInfo(params={"offset": current_count}) + + return None diff --git a/src/codex/resources/projects/remediations/__init__.py b/src/codex/resources/projects/remediations/__init__.py index 3a7c4f9..6c71aad 100644 --- a/src/codex/resources/projects/remediations/__init__.py +++ b/src/codex/resources/projects/remediations/__init__.py @@ -16,6 +16,14 @@ ExpertAnswersResourceWithStreamingResponse, AsyncExpertAnswersResourceWithStreamingResponse, ) +from .expert_reviews import ( + ExpertReviewsResource, + AsyncExpertReviewsResource, + ExpertReviewsResourceWithRawResponse, + AsyncExpertReviewsResourceWithRawResponse, + ExpertReviewsResourceWithStreamingResponse, + AsyncExpertReviewsResourceWithStreamingResponse, +) __all__ = [ "ExpertAnswersResource", @@ -24,6 +32,12 @@ "AsyncExpertAnswersResourceWithRawResponse", "ExpertAnswersResourceWithStreamingResponse", "AsyncExpertAnswersResourceWithStreamingResponse", + "ExpertReviewsResource", + "AsyncExpertReviewsResource", + "ExpertReviewsResourceWithRawResponse", + "AsyncExpertReviewsResourceWithRawResponse", + "ExpertReviewsResourceWithStreamingResponse", + "AsyncExpertReviewsResourceWithStreamingResponse", "RemediationsResource", "AsyncRemediationsResource", "RemediationsResourceWithRawResponse", diff --git a/src/codex/resources/projects/remediations/expert_reviews.py b/src/codex/resources/projects/remediations/expert_reviews.py new file mode 100644 index 0000000..1d0db1b --- /dev/null +++ b/src/codex/resources/projects/remediations/expert_reviews.py @@ -0,0 +1,682 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +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 ....pagination import SyncOffsetPageExpertReviews, AsyncOffsetPageExpertReviews +from ...._base_client import AsyncPaginator, make_request_options +from ....types.projects.remediations import ( + expert_review_edit_params, + expert_review_list_params, + expert_review_create_params, + expert_review_delete_params, +) +from ....types.projects.remediations.expert_review_edit_response import ExpertReviewEditResponse +from ....types.projects.remediations.expert_review_list_response import ExpertReviewListResponse +from ....types.projects.remediations.expert_review_create_response import ExpertReviewCreateResponse +from ....types.projects.remediations.expert_review_retrieve_response import ExpertReviewRetrieveResponse + +__all__ = ["ExpertReviewsResource", "AsyncExpertReviewsResource"] + + +class ExpertReviewsResource(SyncAPIResource): + @cached_property + def with_raw_response(self) -> ExpertReviewsResourceWithRawResponse: + """ + 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/cleanlab/codex-python#accessing-raw-response-data-eg-headers + """ + return ExpertReviewsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ExpertReviewsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/cleanlab/codex-python#with_streaming_response + """ + return ExpertReviewsResourceWithStreamingResponse(self) + + def create( + self, + project_id: str, + *, + original_query_log_id: str, + review_status: Literal["good", "bad"], + generate_guidance: bool | Omit = omit, + explanation: 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, + ) -> ExpertReviewCreateResponse: + """ + Create Expert Review Route + + Args: + original_query_log_id: ID of the original query log + + review_status: Expert review status - 'good' or 'bad' + + explanation: Optional explanation for expert review + + 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"/api/projects/{project_id}/expert_reviews/", + body=maybe_transform( + { + "original_query_log_id": original_query_log_id, + "review_status": review_status, + "explanation": explanation, + }, + expert_review_create_params.ExpertReviewCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + {"generate_guidance": generate_guidance}, expert_review_create_params.ExpertReviewCreateParams + ), + ), + cast_to=ExpertReviewCreateResponse, + ) + + def retrieve( + self, + expert_review_id: str, + *, + project_id: str, + # 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, + ) -> ExpertReviewRetrieveResponse: + """ + Get Expert Review Route + + Args: + 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}") + if not expert_review_id: + raise ValueError(f"Expected a non-empty value for `expert_review_id` but received {expert_review_id!r}") + return self._get( + f"/api/projects/{project_id}/expert_reviews/{expert_review_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ExpertReviewRetrieveResponse, + ) + + def list( + self, + project_id: str, + *, + created_at_end: Union[str, datetime, None] | Omit = omit, + created_at_start: Union[str, datetime, None] | Omit = omit, + last_edited_at_end: Union[str, datetime, None] | Omit = omit, + last_edited_at_start: Union[str, datetime, None] | Omit = omit, + last_edited_by: Optional[str] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + review_status: Optional[List[Literal["good", "bad"]]] | Omit = omit, + sort: Optional[Literal["created_at", "last_edited_at", "resolved_logs_count"]] | 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, + ) -> SyncOffsetPageExpertReviews[ExpertReviewListResponse]: + """ + List Expert Reviews Route + + Args: + created_at_end: Filter expert reviews created at or before this timestamp + + created_at_start: Filter expert reviews created at or after this timestamp + + last_edited_at_end: Filter expert reviews last edited at or before this timestamp + + last_edited_at_start: Filter expert reviews last edited at or after this timestamp + + last_edited_by: Filter expert reviews last edited by user ID + + order: Sort order + + review_status: Filter expert reviews by review status + + sort: Sort expert reviews by field + + 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._get_api_list( + f"/api/projects/{project_id}/expert_reviews/", + page=SyncOffsetPageExpertReviews[ExpertReviewListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "created_at_end": created_at_end, + "created_at_start": created_at_start, + "last_edited_at_end": last_edited_at_end, + "last_edited_at_start": last_edited_at_start, + "last_edited_by": last_edited_by, + "limit": limit, + "offset": offset, + "order": order, + "review_status": review_status, + "sort": sort, + }, + expert_review_list_params.ExpertReviewListParams, + ), + ), + model=ExpertReviewListResponse, + ) + + def delete( + self, + expert_review_id: str, + *, + project_id: str, + original_query_log_id: 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, + ) -> None: + """ + Delete Expert Review Route + + Args: + 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}") + if not expert_review_id: + raise ValueError(f"Expected a non-empty value for `expert_review_id` but received {expert_review_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + f"/api/projects/{project_id}/expert_reviews/{expert_review_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + {"original_query_log_id": original_query_log_id}, + expert_review_delete_params.ExpertReviewDeleteParams, + ), + ), + cast_to=NoneType, + ) + + def edit( + self, + expert_review_id: str, + *, + project_id: str, + explanation: Optional[str] | Omit = omit, + review_status: Optional[Literal["good", "bad"]] | 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, + ) -> ExpertReviewEditResponse: + """ + Update Expert Review Route + + Args: + 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}") + if not expert_review_id: + raise ValueError(f"Expected a non-empty value for `expert_review_id` but received {expert_review_id!r}") + return self._patch( + f"/api/projects/{project_id}/expert_reviews/{expert_review_id}", + body=maybe_transform( + { + "explanation": explanation, + "review_status": review_status, + }, + expert_review_edit_params.ExpertReviewEditParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ExpertReviewEditResponse, + ) + + +class AsyncExpertReviewsResource(AsyncAPIResource): + @cached_property + def with_raw_response(self) -> AsyncExpertReviewsResourceWithRawResponse: + """ + 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/cleanlab/codex-python#accessing-raw-response-data-eg-headers + """ + return AsyncExpertReviewsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncExpertReviewsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/cleanlab/codex-python#with_streaming_response + """ + return AsyncExpertReviewsResourceWithStreamingResponse(self) + + async def create( + self, + project_id: str, + *, + original_query_log_id: str, + review_status: Literal["good", "bad"], + generate_guidance: bool | Omit = omit, + explanation: 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, + ) -> ExpertReviewCreateResponse: + """ + Create Expert Review Route + + Args: + original_query_log_id: ID of the original query log + + review_status: Expert review status - 'good' or 'bad' + + explanation: Optional explanation for expert review + + 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"/api/projects/{project_id}/expert_reviews/", + body=await async_maybe_transform( + { + "original_query_log_id": original_query_log_id, + "review_status": review_status, + "explanation": explanation, + }, + expert_review_create_params.ExpertReviewCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"generate_guidance": generate_guidance}, expert_review_create_params.ExpertReviewCreateParams + ), + ), + cast_to=ExpertReviewCreateResponse, + ) + + async def retrieve( + self, + expert_review_id: str, + *, + project_id: str, + # 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, + ) -> ExpertReviewRetrieveResponse: + """ + Get Expert Review Route + + Args: + 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}") + if not expert_review_id: + raise ValueError(f"Expected a non-empty value for `expert_review_id` but received {expert_review_id!r}") + return await self._get( + f"/api/projects/{project_id}/expert_reviews/{expert_review_id}", + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ExpertReviewRetrieveResponse, + ) + + def list( + self, + project_id: str, + *, + created_at_end: Union[str, datetime, None] | Omit = omit, + created_at_start: Union[str, datetime, None] | Omit = omit, + last_edited_at_end: Union[str, datetime, None] | Omit = omit, + last_edited_at_start: Union[str, datetime, None] | Omit = omit, + last_edited_by: Optional[str] | Omit = omit, + limit: int | Omit = omit, + offset: int | Omit = omit, + order: Literal["asc", "desc"] | Omit = omit, + review_status: Optional[List[Literal["good", "bad"]]] | Omit = omit, + sort: Optional[Literal["created_at", "last_edited_at", "resolved_logs_count"]] | 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, + ) -> AsyncPaginator[ExpertReviewListResponse, AsyncOffsetPageExpertReviews[ExpertReviewListResponse]]: + """ + List Expert Reviews Route + + Args: + created_at_end: Filter expert reviews created at or before this timestamp + + created_at_start: Filter expert reviews created at or after this timestamp + + last_edited_at_end: Filter expert reviews last edited at or before this timestamp + + last_edited_at_start: Filter expert reviews last edited at or after this timestamp + + last_edited_by: Filter expert reviews last edited by user ID + + order: Sort order + + review_status: Filter expert reviews by review status + + sort: Sort expert reviews by field + + 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._get_api_list( + f"/api/projects/{project_id}/expert_reviews/", + page=AsyncOffsetPageExpertReviews[ExpertReviewListResponse], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "created_at_end": created_at_end, + "created_at_start": created_at_start, + "last_edited_at_end": last_edited_at_end, + "last_edited_at_start": last_edited_at_start, + "last_edited_by": last_edited_by, + "limit": limit, + "offset": offset, + "order": order, + "review_status": review_status, + "sort": sort, + }, + expert_review_list_params.ExpertReviewListParams, + ), + ), + model=ExpertReviewListResponse, + ) + + async def delete( + self, + expert_review_id: str, + *, + project_id: str, + original_query_log_id: 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, + ) -> None: + """ + Delete Expert Review Route + + Args: + 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}") + if not expert_review_id: + raise ValueError(f"Expected a non-empty value for `expert_review_id` but received {expert_review_id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + f"/api/projects/{project_id}/expert_reviews/{expert_review_id}", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"original_query_log_id": original_query_log_id}, + expert_review_delete_params.ExpertReviewDeleteParams, + ), + ), + cast_to=NoneType, + ) + + async def edit( + self, + expert_review_id: str, + *, + project_id: str, + explanation: Optional[str] | Omit = omit, + review_status: Optional[Literal["good", "bad"]] | 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, + ) -> ExpertReviewEditResponse: + """ + Update Expert Review Route + + Args: + 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}") + if not expert_review_id: + raise ValueError(f"Expected a non-empty value for `expert_review_id` but received {expert_review_id!r}") + return await self._patch( + f"/api/projects/{project_id}/expert_reviews/{expert_review_id}", + body=await async_maybe_transform( + { + "explanation": explanation, + "review_status": review_status, + }, + expert_review_edit_params.ExpertReviewEditParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ExpertReviewEditResponse, + ) + + +class ExpertReviewsResourceWithRawResponse: + def __init__(self, expert_reviews: ExpertReviewsResource) -> None: + self._expert_reviews = expert_reviews + + self.create = to_raw_response_wrapper( + expert_reviews.create, + ) + self.retrieve = to_raw_response_wrapper( + expert_reviews.retrieve, + ) + self.list = to_raw_response_wrapper( + expert_reviews.list, + ) + self.delete = to_raw_response_wrapper( + expert_reviews.delete, + ) + self.edit = to_raw_response_wrapper( + expert_reviews.edit, + ) + + +class AsyncExpertReviewsResourceWithRawResponse: + def __init__(self, expert_reviews: AsyncExpertReviewsResource) -> None: + self._expert_reviews = expert_reviews + + self.create = async_to_raw_response_wrapper( + expert_reviews.create, + ) + self.retrieve = async_to_raw_response_wrapper( + expert_reviews.retrieve, + ) + self.list = async_to_raw_response_wrapper( + expert_reviews.list, + ) + self.delete = async_to_raw_response_wrapper( + expert_reviews.delete, + ) + self.edit = async_to_raw_response_wrapper( + expert_reviews.edit, + ) + + +class ExpertReviewsResourceWithStreamingResponse: + def __init__(self, expert_reviews: ExpertReviewsResource) -> None: + self._expert_reviews = expert_reviews + + self.create = to_streamed_response_wrapper( + expert_reviews.create, + ) + self.retrieve = to_streamed_response_wrapper( + expert_reviews.retrieve, + ) + self.list = to_streamed_response_wrapper( + expert_reviews.list, + ) + self.delete = to_streamed_response_wrapper( + expert_reviews.delete, + ) + self.edit = to_streamed_response_wrapper( + expert_reviews.edit, + ) + + +class AsyncExpertReviewsResourceWithStreamingResponse: + def __init__(self, expert_reviews: AsyncExpertReviewsResource) -> None: + self._expert_reviews = expert_reviews + + self.create = async_to_streamed_response_wrapper( + expert_reviews.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + expert_reviews.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + expert_reviews.list, + ) + self.delete = async_to_streamed_response_wrapper( + expert_reviews.delete, + ) + self.edit = async_to_streamed_response_wrapper( + expert_reviews.edit, + ) diff --git a/src/codex/resources/projects/remediations/remediations.py b/src/codex/resources/projects/remediations/remediations.py index 23873af..f02cba8 100644 --- a/src/codex/resources/projects/remediations/remediations.py +++ b/src/codex/resources/projects/remediations/remediations.py @@ -28,6 +28,14 @@ ExpertAnswersResourceWithStreamingResponse, AsyncExpertAnswersResourceWithStreamingResponse, ) +from .expert_reviews import ( + ExpertReviewsResource, + AsyncExpertReviewsResource, + ExpertReviewsResourceWithRawResponse, + AsyncExpertReviewsResourceWithRawResponse, + ExpertReviewsResourceWithStreamingResponse, + AsyncExpertReviewsResourceWithStreamingResponse, +) from ...._base_client import AsyncPaginator, make_request_options from ....types.projects import ( remediation_list_params, @@ -54,6 +62,10 @@ class RemediationsResource(SyncAPIResource): def expert_answers(self) -> ExpertAnswersResource: return ExpertAnswersResource(self._client) + @cached_property + def expert_reviews(self) -> ExpertReviewsResource: + return ExpertReviewsResource(self._client) + @cached_property def with_raw_response(self) -> RemediationsResourceWithRawResponse: """ @@ -539,6 +551,10 @@ class AsyncRemediationsResource(AsyncAPIResource): def expert_answers(self) -> AsyncExpertAnswersResource: return AsyncExpertAnswersResource(self._client) + @cached_property + def expert_reviews(self) -> AsyncExpertReviewsResource: + return AsyncExpertReviewsResource(self._client) + @cached_property def with_raw_response(self) -> AsyncRemediationsResourceWithRawResponse: """ @@ -1085,6 +1101,10 @@ def __init__(self, remediations: RemediationsResource) -> None: def expert_answers(self) -> ExpertAnswersResourceWithRawResponse: return ExpertAnswersResourceWithRawResponse(self._remediations.expert_answers) + @cached_property + def expert_reviews(self) -> ExpertReviewsResourceWithRawResponse: + return ExpertReviewsResourceWithRawResponse(self._remediations.expert_reviews) + class AsyncRemediationsResourceWithRawResponse: def __init__(self, remediations: AsyncRemediationsResource) -> None: @@ -1150,6 +1170,10 @@ def __init__(self, remediations: AsyncRemediationsResource) -> None: def expert_answers(self) -> AsyncExpertAnswersResourceWithRawResponse: return AsyncExpertAnswersResourceWithRawResponse(self._remediations.expert_answers) + @cached_property + def expert_reviews(self) -> AsyncExpertReviewsResourceWithRawResponse: + return AsyncExpertReviewsResourceWithRawResponse(self._remediations.expert_reviews) + class RemediationsResourceWithStreamingResponse: def __init__(self, remediations: RemediationsResource) -> None: @@ -1215,6 +1239,10 @@ def __init__(self, remediations: RemediationsResource) -> None: def expert_answers(self) -> ExpertAnswersResourceWithStreamingResponse: return ExpertAnswersResourceWithStreamingResponse(self._remediations.expert_answers) + @cached_property + def expert_reviews(self) -> ExpertReviewsResourceWithStreamingResponse: + return ExpertReviewsResourceWithStreamingResponse(self._remediations.expert_reviews) + class AsyncRemediationsResourceWithStreamingResponse: def __init__(self, remediations: AsyncRemediationsResource) -> None: @@ -1279,3 +1307,7 @@ def __init__(self, remediations: AsyncRemediationsResource) -> None: @cached_property def expert_answers(self) -> AsyncExpertAnswersResourceWithStreamingResponse: return AsyncExpertAnswersResourceWithStreamingResponse(self._remediations.expert_answers) + + @cached_property + def expert_reviews(self) -> AsyncExpertReviewsResourceWithStreamingResponse: + return AsyncExpertReviewsResourceWithStreamingResponse(self._remediations.expert_reviews) diff --git a/src/codex/types/projects/remediations/__init__.py b/src/codex/types/projects/remediations/__init__.py index da14220..520c597 100644 --- a/src/codex/types/projects/remediations/__init__.py +++ b/src/codex/types/projects/remediations/__init__.py @@ -3,13 +3,21 @@ from __future__ import annotations from .expert_answer_list_params import ExpertAnswerListParams as ExpertAnswerListParams +from .expert_review_edit_params import ExpertReviewEditParams as ExpertReviewEditParams +from .expert_review_list_params import ExpertReviewListParams as ExpertReviewListParams from .expert_answer_create_params import ExpertAnswerCreateParams as ExpertAnswerCreateParams from .expert_answer_list_response import ExpertAnswerListResponse as ExpertAnswerListResponse +from .expert_review_create_params import ExpertReviewCreateParams as ExpertReviewCreateParams +from .expert_review_delete_params import ExpertReviewDeleteParams as ExpertReviewDeleteParams +from .expert_review_edit_response import ExpertReviewEditResponse as ExpertReviewEditResponse +from .expert_review_list_response import ExpertReviewListResponse as ExpertReviewListResponse from .expert_answer_pause_response import ExpertAnswerPauseResponse as ExpertAnswerPauseResponse from .expert_answer_create_response import ExpertAnswerCreateResponse as ExpertAnswerCreateResponse +from .expert_review_create_response import ExpertReviewCreateResponse as ExpertReviewCreateResponse from .expert_answer_publish_response import ExpertAnswerPublishResponse as ExpertAnswerPublishResponse from .expert_answer_unpause_response import ExpertAnswerUnpauseResponse as ExpertAnswerUnpauseResponse from .expert_answer_retrieve_response import ExpertAnswerRetrieveResponse as ExpertAnswerRetrieveResponse +from .expert_review_retrieve_response import ExpertReviewRetrieveResponse as ExpertReviewRetrieveResponse from .expert_answer_edit_answer_params import ExpertAnswerEditAnswerParams as ExpertAnswerEditAnswerParams from .expert_answer_edit_answer_response import ExpertAnswerEditAnswerResponse as ExpertAnswerEditAnswerResponse from .expert_answer_edit_draft_answer_params import ( diff --git a/src/codex/types/projects/remediations/expert_review_create_params.py b/src/codex/types/projects/remediations/expert_review_create_params.py new file mode 100644 index 0000000..c871bd8 --- /dev/null +++ b/src/codex/types/projects/remediations/expert_review_create_params.py @@ -0,0 +1,21 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ExpertReviewCreateParams"] + + +class ExpertReviewCreateParams(TypedDict, total=False): + original_query_log_id: Required[str] + """ID of the original query log""" + + review_status: Required[Literal["good", "bad"]] + """Expert review status - 'good' or 'bad'""" + + generate_guidance: bool + + explanation: Optional[str] + """Optional explanation for expert review""" diff --git a/src/codex/types/projects/remediations/expert_review_create_response.py b/src/codex/types/projects/remediations/expert_review_create_response.py new file mode 100644 index 0000000..154d8e0 --- /dev/null +++ b/src/codex/types/projects/remediations/expert_review_create_response.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ExpertReviewCreateResponse"] + + +class ExpertReviewCreateResponse(BaseModel): + id: str + + created_at: datetime + + last_edited_at: datetime + + last_edited_by: Optional[str] = None + + project_id: str + + review_status: Literal["good", "bad"] + """Expert review status - 'good' or 'bad'""" + + deleted_at: Optional[datetime] = None + + explanation: Optional[str] = None + """Optional explanation for expert review""" diff --git a/src/codex/types/projects/remediations/expert_review_delete_params.py b/src/codex/types/projects/remediations/expert_review_delete_params.py new file mode 100644 index 0000000..440bf07 --- /dev/null +++ b/src/codex/types/projects/remediations/expert_review_delete_params.py @@ -0,0 +1,14 @@ +# 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 Required, TypedDict + +__all__ = ["ExpertReviewDeleteParams"] + + +class ExpertReviewDeleteParams(TypedDict, total=False): + project_id: Required[str] + + original_query_log_id: Optional[str] diff --git a/src/codex/types/projects/remediations/expert_review_edit_params.py b/src/codex/types/projects/remediations/expert_review_edit_params.py new file mode 100644 index 0000000..d0b48b8 --- /dev/null +++ b/src/codex/types/projects/remediations/expert_review_edit_params.py @@ -0,0 +1,16 @@ +# 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 Literal, Required, TypedDict + +__all__ = ["ExpertReviewEditParams"] + + +class ExpertReviewEditParams(TypedDict, total=False): + project_id: Required[str] + + explanation: Optional[str] + + review_status: Optional[Literal["good", "bad"]] diff --git a/src/codex/types/projects/remediations/expert_review_edit_response.py b/src/codex/types/projects/remediations/expert_review_edit_response.py new file mode 100644 index 0000000..1c3d845 --- /dev/null +++ b/src/codex/types/projects/remediations/expert_review_edit_response.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ExpertReviewEditResponse"] + + +class ExpertReviewEditResponse(BaseModel): + id: str + + created_at: datetime + + last_edited_at: datetime + + last_edited_by: Optional[str] = None + + project_id: str + + review_status: Literal["good", "bad"] + """Expert review status - 'good' or 'bad'""" + + deleted_at: Optional[datetime] = None + + explanation: Optional[str] = None + """Optional explanation for expert review""" diff --git a/src/codex/types/projects/remediations/expert_review_list_params.py b/src/codex/types/projects/remediations/expert_review_list_params.py new file mode 100644 index 0000000..b316b2f --- /dev/null +++ b/src/codex/types/projects/remediations/expert_review_list_params.py @@ -0,0 +1,41 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Optional +from datetime import datetime +from typing_extensions import Literal, Annotated, TypedDict + +from ...._utils import PropertyInfo + +__all__ = ["ExpertReviewListParams"] + + +class ExpertReviewListParams(TypedDict, total=False): + created_at_end: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """Filter expert reviews created at or before this timestamp""" + + created_at_start: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """Filter expert reviews created at or after this timestamp""" + + last_edited_at_end: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """Filter expert reviews last edited at or before this timestamp""" + + last_edited_at_start: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] + """Filter expert reviews last edited at or after this timestamp""" + + last_edited_by: Optional[str] + """Filter expert reviews last edited by user ID""" + + limit: int + + offset: int + + order: Literal["asc", "desc"] + """Sort order""" + + review_status: Optional[List[Literal["good", "bad"]]] + """Filter expert reviews by review status""" + + sort: Optional[Literal["created_at", "last_edited_at", "resolved_logs_count"]] + """Sort expert reviews by field""" diff --git a/src/codex/types/projects/remediations/expert_review_list_response.py b/src/codex/types/projects/remediations/expert_review_list_response.py new file mode 100644 index 0000000..99d26ab --- /dev/null +++ b/src/codex/types/projects/remediations/expert_review_list_response.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ExpertReviewListResponse"] + + +class ExpertReviewListResponse(BaseModel): + id: str + + created_at: datetime + + evaluated_response: Optional[str] = None + + last_edited_at: datetime + + last_edited_by: Optional[str] = None + + project_id: str + + query: str + + resolved_logs_count: int + + review_status: Literal["good", "bad"] + """Expert review status - 'good' or 'bad'""" + + deleted_at: Optional[datetime] = None + + explanation: Optional[str] = None + """Optional explanation for expert review""" diff --git a/src/codex/types/projects/remediations/expert_review_retrieve_response.py b/src/codex/types/projects/remediations/expert_review_retrieve_response.py new file mode 100644 index 0000000..9cb0da6 --- /dev/null +++ b/src/codex/types/projects/remediations/expert_review_retrieve_response.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ...._models import BaseModel + +__all__ = ["ExpertReviewRetrieveResponse"] + + +class ExpertReviewRetrieveResponse(BaseModel): + id: str + + created_at: datetime + + evaluated_response: Optional[str] = None + + last_edited_at: datetime + + last_edited_by: Optional[str] = None + + project_id: str + + query: str + + resolved_logs_count: int + + review_status: Literal["good", "bad"] + """Expert review status - 'good' or 'bad'""" + + deleted_at: Optional[datetime] = None + + explanation: Optional[str] = None + """Optional explanation for expert review""" diff --git a/tests/api_resources/projects/remediations/test_expert_reviews.py b/tests/api_resources/projects/remediations/test_expert_reviews.py new file mode 100644 index 0000000..f65b0fb --- /dev/null +++ b/tests/api_resources/projects/remediations/test_expert_reviews.py @@ -0,0 +1,631 @@ +# 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 codex import Codex, AsyncCodex +from tests.utils import assert_matches_type +from codex._utils import parse_datetime +from codex.pagination import SyncOffsetPageExpertReviews, AsyncOffsetPageExpertReviews +from codex.types.projects.remediations import ( + ExpertReviewEditResponse, + ExpertReviewListResponse, + ExpertReviewCreateResponse, + ExpertReviewRetrieveResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestExpertReviews: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_create(self, client: Codex) -> None: + expert_review = client.projects.remediations.expert_reviews.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + original_query_log_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + review_status="good", + ) + assert_matches_type(ExpertReviewCreateResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Codex) -> None: + expert_review = client.projects.remediations.expert_reviews.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + original_query_log_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + review_status="good", + generate_guidance=True, + explanation="explanation", + ) + assert_matches_type(ExpertReviewCreateResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_create(self, client: Codex) -> None: + response = client.projects.remediations.expert_reviews.with_raw_response.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + original_query_log_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + review_status="good", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + expert_review = response.parse() + assert_matches_type(ExpertReviewCreateResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Codex) -> None: + with client.projects.remediations.expert_reviews.with_streaming_response.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + original_query_log_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + review_status="good", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + expert_review = response.parse() + assert_matches_type(ExpertReviewCreateResponse, expert_review, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_create(self, client: Codex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.projects.remediations.expert_reviews.with_raw_response.create( + project_id="", + original_query_log_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + review_status="good", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_retrieve(self, client: Codex) -> None: + expert_review = client.projects.remediations.expert_reviews.retrieve( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ExpertReviewRetrieveResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Codex) -> None: + response = client.projects.remediations.expert_reviews.with_raw_response.retrieve( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + expert_review = response.parse() + assert_matches_type(ExpertReviewRetrieveResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Codex) -> None: + with client.projects.remediations.expert_reviews.with_streaming_response.retrieve( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + expert_review = response.parse() + assert_matches_type(ExpertReviewRetrieveResponse, expert_review, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Codex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.projects.remediations.expert_reviews.with_raw_response.retrieve( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `expert_review_id` but received ''"): + client.projects.remediations.expert_reviews.with_raw_response.retrieve( + expert_review_id="", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_list(self, client: Codex) -> None: + expert_review = client.projects.remediations.expert_reviews.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(SyncOffsetPageExpertReviews[ExpertReviewListResponse], expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Codex) -> None: + expert_review = client.projects.remediations.expert_reviews.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + created_at_end=parse_datetime("2019-12-27T18:11:19.117Z"), + created_at_start=parse_datetime("2019-12-27T18:11:19.117Z"), + last_edited_at_end=parse_datetime("2019-12-27T18:11:19.117Z"), + last_edited_at_start=parse_datetime("2019-12-27T18:11:19.117Z"), + last_edited_by="last_edited_by", + limit=1, + offset=0, + order="asc", + review_status=["good"], + sort="created_at", + ) + assert_matches_type(SyncOffsetPageExpertReviews[ExpertReviewListResponse], expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_list(self, client: Codex) -> None: + response = client.projects.remediations.expert_reviews.with_raw_response.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + expert_review = response.parse() + assert_matches_type(SyncOffsetPageExpertReviews[ExpertReviewListResponse], expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Codex) -> None: + with client.projects.remediations.expert_reviews.with_streaming_response.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + expert_review = response.parse() + assert_matches_type(SyncOffsetPageExpertReviews[ExpertReviewListResponse], expert_review, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_list(self, client: Codex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.projects.remediations.expert_reviews.with_raw_response.list( + project_id="", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_delete(self, client: Codex) -> None: + expert_review = client.projects.remediations.expert_reviews.delete( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert expert_review is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_delete_with_all_params(self, client: Codex) -> None: + expert_review = client.projects.remediations.expert_reviews.delete( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + original_query_log_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert expert_review is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_delete(self, client: Codex) -> None: + response = client.projects.remediations.expert_reviews.with_raw_response.delete( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + expert_review = response.parse() + assert expert_review is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_delete(self, client: Codex) -> None: + with client.projects.remediations.expert_reviews.with_streaming_response.delete( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + expert_review = response.parse() + assert expert_review is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_delete(self, client: Codex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.projects.remediations.expert_reviews.with_raw_response.delete( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `expert_review_id` but received ''"): + client.projects.remediations.expert_reviews.with_raw_response.delete( + expert_review_id="", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_edit(self, client: Codex) -> None: + expert_review = client.projects.remediations.expert_reviews.edit( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ExpertReviewEditResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_method_edit_with_all_params(self, client: Codex) -> None: + expert_review = client.projects.remediations.expert_reviews.edit( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + explanation="explanation", + review_status="good", + ) + assert_matches_type(ExpertReviewEditResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_raw_response_edit(self, client: Codex) -> None: + response = client.projects.remediations.expert_reviews.with_raw_response.edit( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + expert_review = response.parse() + assert_matches_type(ExpertReviewEditResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_streaming_response_edit(self, client: Codex) -> None: + with client.projects.remediations.expert_reviews.with_streaming_response.edit( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + expert_review = response.parse() + assert_matches_type(ExpertReviewEditResponse, expert_review, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + def test_path_params_edit(self, client: Codex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + client.projects.remediations.expert_reviews.with_raw_response.edit( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `expert_review_id` but received ''"): + client.projects.remediations.expert_reviews.with_raw_response.edit( + expert_review_id="", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + +class TestAsyncExpertReviews: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncCodex) -> None: + expert_review = await async_client.projects.remediations.expert_reviews.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + original_query_log_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + review_status="good", + ) + assert_matches_type(ExpertReviewCreateResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncCodex) -> None: + expert_review = await async_client.projects.remediations.expert_reviews.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + original_query_log_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + review_status="good", + generate_guidance=True, + explanation="explanation", + ) + assert_matches_type(ExpertReviewCreateResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncCodex) -> None: + response = await async_client.projects.remediations.expert_reviews.with_raw_response.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + original_query_log_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + review_status="good", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + expert_review = await response.parse() + assert_matches_type(ExpertReviewCreateResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncCodex) -> None: + async with async_client.projects.remediations.expert_reviews.with_streaming_response.create( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + original_query_log_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + review_status="good", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + expert_review = await response.parse() + assert_matches_type(ExpertReviewCreateResponse, expert_review, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_create(self, async_client: AsyncCodex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.projects.remediations.expert_reviews.with_raw_response.create( + project_id="", + original_query_log_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + review_status="good", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncCodex) -> None: + expert_review = await async_client.projects.remediations.expert_reviews.retrieve( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ExpertReviewRetrieveResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncCodex) -> None: + response = await async_client.projects.remediations.expert_reviews.with_raw_response.retrieve( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + expert_review = await response.parse() + assert_matches_type(ExpertReviewRetrieveResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncCodex) -> None: + async with async_client.projects.remediations.expert_reviews.with_streaming_response.retrieve( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + expert_review = await response.parse() + assert_matches_type(ExpertReviewRetrieveResponse, expert_review, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncCodex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.projects.remediations.expert_reviews.with_raw_response.retrieve( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `expert_review_id` but received ''"): + await async_client.projects.remediations.expert_reviews.with_raw_response.retrieve( + expert_review_id="", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncCodex) -> None: + expert_review = await async_client.projects.remediations.expert_reviews.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(AsyncOffsetPageExpertReviews[ExpertReviewListResponse], expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncCodex) -> None: + expert_review = await async_client.projects.remediations.expert_reviews.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + created_at_end=parse_datetime("2019-12-27T18:11:19.117Z"), + created_at_start=parse_datetime("2019-12-27T18:11:19.117Z"), + last_edited_at_end=parse_datetime("2019-12-27T18:11:19.117Z"), + last_edited_at_start=parse_datetime("2019-12-27T18:11:19.117Z"), + last_edited_by="last_edited_by", + limit=1, + offset=0, + order="asc", + review_status=["good"], + sort="created_at", + ) + assert_matches_type(AsyncOffsetPageExpertReviews[ExpertReviewListResponse], expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncCodex) -> None: + response = await async_client.projects.remediations.expert_reviews.with_raw_response.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + expert_review = await response.parse() + assert_matches_type(AsyncOffsetPageExpertReviews[ExpertReviewListResponse], expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncCodex) -> None: + async with async_client.projects.remediations.expert_reviews.with_streaming_response.list( + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + expert_review = await response.parse() + assert_matches_type( + AsyncOffsetPageExpertReviews[ExpertReviewListResponse], expert_review, path=["response"] + ) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_list(self, async_client: AsyncCodex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.projects.remediations.expert_reviews.with_raw_response.list( + project_id="", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_delete(self, async_client: AsyncCodex) -> None: + expert_review = await async_client.projects.remediations.expert_reviews.delete( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert expert_review is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncCodex) -> None: + expert_review = await async_client.projects.remediations.expert_reviews.delete( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + original_query_log_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert expert_review is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncCodex) -> None: + response = await async_client.projects.remediations.expert_reviews.with_raw_response.delete( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + expert_review = await response.parse() + assert expert_review is None + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncCodex) -> None: + async with async_client.projects.remediations.expert_reviews.with_streaming_response.delete( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + expert_review = await response.parse() + assert expert_review is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_delete(self, async_client: AsyncCodex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.projects.remediations.expert_reviews.with_raw_response.delete( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `expert_review_id` but received ''"): + await async_client.projects.remediations.expert_reviews.with_raw_response.delete( + expert_review_id="", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_edit(self, async_client: AsyncCodex) -> None: + expert_review = await async_client.projects.remediations.expert_reviews.edit( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ExpertReviewEditResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_method_edit_with_all_params(self, async_client: AsyncCodex) -> None: + expert_review = await async_client.projects.remediations.expert_reviews.edit( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + explanation="explanation", + review_status="good", + ) + assert_matches_type(ExpertReviewEditResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_raw_response_edit(self, async_client: AsyncCodex) -> None: + response = await async_client.projects.remediations.expert_reviews.with_raw_response.edit( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + expert_review = await response.parse() + assert_matches_type(ExpertReviewEditResponse, expert_review, path=["response"]) + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_streaming_response_edit(self, async_client: AsyncCodex) -> None: + async with async_client.projects.remediations.expert_reviews.with_streaming_response.edit( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + expert_review = await response.parse() + assert_matches_type(ExpertReviewEditResponse, expert_review, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Prism tests are disabled") + @parametrize + async def test_path_params_edit(self, async_client: AsyncCodex) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `project_id` but received ''"): + await async_client.projects.remediations.expert_reviews.with_raw_response.edit( + expert_review_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + project_id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `expert_review_id` but received ''"): + await async_client.projects.remediations.expert_reviews.with_raw_response.edit( + expert_review_id="", + project_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) From f74f2840241812da3d7afeb4b50123aed69056fc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 19 Nov 2025 19:07:33 +0000 Subject: [PATCH 3/3] release: 0.1.0-alpha.34 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 9 +++++++++ pyproject.toml | 2 +- src/codex/_version.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ff4f9a5..36b2aff 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.33" + ".": "0.1.0-alpha.34" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 306f329..7782cb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 0.1.0-alpha.34 (2025-11-19) + +Full Changelog: [v0.1.0-alpha.33...v0.1.0-alpha.34](https://github.com/cleanlab/codex-python/compare/v0.1.0-alpha.33...v0.1.0-alpha.34) + +### Features + +* **api:** add expert review endpoints ([cda6f91](https://github.com/cleanlab/codex-python/commit/cda6f911fe678318779d23de9ecc77fb15594fa1)) +* **api:** api update ([5848aac](https://github.com/cleanlab/codex-python/commit/5848aac2eb02a789c20951056a7b802985d8b2ab)) + ## 0.1.0-alpha.33 (2025-11-18) Full Changelog: [v0.1.0-alpha.32...v0.1.0-alpha.33](https://github.com/cleanlab/codex-python/compare/v0.1.0-alpha.32...v0.1.0-alpha.33) diff --git a/pyproject.toml b/pyproject.toml index efd2e79..5fb2418 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "codex-sdk" -version = "0.1.0-alpha.33" +version = "0.1.0-alpha.34" description = "Internal SDK used within cleanlab-codex package. Refer to https://pypi.org/project/cleanlab-codex/ instead." dynamic = ["readme"] license = "MIT" diff --git a/src/codex/_version.py b/src/codex/_version.py index 45fdfee..c2ea81e 100644 --- a/src/codex/_version.py +++ b/src/codex/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "codex" -__version__ = "0.1.0-alpha.33" # x-release-please-version +__version__ = "0.1.0-alpha.34" # x-release-please-version