Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 43 additions & 1 deletion plane/models/query_params.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Query parameter DTOs for list/retrieve endpoints."""

from pydantic import BaseModel, ConfigDict, Field
from pydantic import BaseModel, ConfigDict, Field, model_serializer


class BaseQueryParams(BaseModel):
Expand Down Expand Up @@ -62,6 +62,48 @@ class WorkItemQueryParams(PaginatedQueryParams):

model_config = ConfigDict(extra="ignore", populate_by_name=True)

assignee_id__in: list[str] | None = Field(
None,
description="Filter by assignee UUIDs",
)
state_id__in: list[str] | None = Field(
None,
description="Filter by state UUIDs",
)
state_group__in: list[str] | None = Field(
None,
description="Filter by state groups (backlog, unstarted, started, completed, cancelled)",
)
priority__in: list[str] | None = Field(
None,
description="Filter by priority levels (urgent, high, medium, low, none)",
)
Comment on lines +73 to +80
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

state_group__in and priority__in are typed as list[str], but the codebase already defines constrained Literal types (GroupEnum, PriorityEnum) used across models. Consider typing these as list[GroupEnum] | None and list[PriorityEnum] | None to prevent invalid values at compile/validation time and keep consistency with the rest of the SDK.

Copilot uses AI. Check for mistakes.
label_id__in: list[str] | None = Field(
None,
description="Filter by label UUIDs",
)
created_by_id__in: list[str] | None = Field(
None,
description="Filter by creator user UUIDs",
)
is_draft: bool | None = Field(
None,
description="Filter by draft status",
)
is_archived: bool | None = Field(
None,
description="Filter by archived status",
)

@model_serializer(mode="wrap")
def _serialize(self, handler): # type: ignore[no-untyped-def]
"""Serialize list fields as comma-separated strings for django-filters."""
Comment on lines +98 to +100
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @model_serializer is currently untyped and relies on # type: ignore[no-untyped-def], which conflicts with the repo’s strict mypy config. Please type the serializer signature (e.g., using Pydantic’s SerializerFunctionWrapHandler and optional SerializationInfo) so we can remove the type ignore and keep type safety.

Copilot uses AI. Check for mistakes.
data = handler(self)
for key, value in data.items():
if isinstance(value, list):
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The model-level serializer converts any list-valued field into a comma-separated string. That’s fine for the current __in filters, but it will also affect any future list fields added to WorkItemQueryParams (even if the API expects repeated query params instead of CSV). Consider limiting this conversion to the known *__in keys (or an explicit allowlist) to avoid surprising serialization changes later.

Suggested change
if isinstance(value, list):
if key.endswith("__in") and isinstance(value, list):

Copilot uses AI. Check for mistakes.
data[key] = ",".join(str(v) for v in value)
return data
Comment on lines +98 to +105
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New serialization behavior (converting list filters to comma-separated strings) isn’t covered by tests. Please add a unit test that asserts WorkItemQueryParams(assignee_id__in=[...]).model_dump(exclude_none=True) produces a comma-separated string, since this behavior is critical for server-side filtering to work with requests query encoding.

Copilot uses AI. Check for mistakes.


class RetrieveQueryParams(BaseQueryParams):
"""Query parameters for retrieve endpoints."""
Expand Down
Loading