refactor(api): migrate workspace account auxiliary responses to BaseModel#35220
Conversation
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-04-14 21:17:32.597365981 +0000
+++ /tmp/pyrefly_pr.txt 2026-04-14 21:17:23.934156242 +0000
@@ -16,6 +16,8 @@
--> controllers/console/setup.py:65:2
ERROR Object of class `MissingRouter` has no attribute `get` [missing-attribute]
--> controllers/console/version.py:30:2
+ERROR Unexpected keyword argument `session` in function `services.account_service.AccountService.get_account_by_email_with_case_fallback` [unexpected-keyword]
+ --> controllers/console/workspace/account.py:597:94
ERROR Object of class `object` has no attribute `value` [missing-attribute]
--> controllers/service_api/app/conversation.py:87:24
ERROR Class member `EasyUIBasedGenerateTaskPipeline._application_generate_entity` overrides parent class `BasedGenerateTaskPipeline` in an inconsistent manner [bad-override]
|
Pyrefly DiffNo changes detected. |
There was a problem hiding this comment.
Pull request overview
Refines the BaseModel migration work in the workspace account console controller by keeping auxiliary response payloads on ResponseModel, tightening education autocomplete response shape, and centralizing timestamp normalization for billing/integration responses.
Changes:
- Added
_to_timestampnormalization to supportdatetime | int | ISO stringinputs for billing/integration timestamps. - Updated account integrate list serialization to validate the full payload via
AccountIntegrateListResponse.model_validate(...). - Made education autocomplete response fields required (
data,curr_page,has_next) and removed{}fallbacks for billing responses.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def _serialize_account(account) -> dict: | ||
| return AccountResponse.model_validate(account, from_attributes=True).model_dump(mode="json") |
There was a problem hiding this comment.
_serialize_account now returns an unparameterized dict, which effectively becomes dict[Any, Any] and loses the guarantee that keys are strings (and makes type-checking less useful). Consider keeping the more precise return type (e.g., dict[str, Any]) to preserve the intent and avoid accidental non-string keys/values creeping in.
| def _to_timestamp(value: datetime | int | str | None) -> int | None: | ||
| if value is None: | ||
| return None | ||
| if isinstance(value, int): | ||
| return value | ||
| if isinstance(value, datetime): | ||
| return int(value.timestamp()) | ||
| return value | ||
| return int(datetime.fromisoformat(value).astimezone(pytz.utc).timestamp()) |
There was a problem hiding this comment.
_to_timestamp uses datetime.fromisoformat(value).astimezone(pytz.utc) for string inputs, which will raise for common ISO variants like a trailing Z (e.g., 2024-01-01T00:00:00Z) and for naive datetimes (no tzinfo). This can cause response validation to fail and return 500s for billing/integration responses. Consider normalizing Z to +00:00, handling naive values by assuming UTC (or explicitly rejecting them with a clear error), and wrapping parsing in a try/except to produce a controlled failure mode.
Part of #28015
Summary
Refine the
api/controllers/console/workspace/account.pyBaseModel migration for workspace account auxiliary responses.AccountIntegrate*,Education*) on PydanticResponseModel.datetime | int | ISO string.AccountIntegrateListResponse.model_validate(...).data,curr_page,has_nextrequired).get_account_by_email_with_case_fallback(...)in change-email flow.Checklist
make lintandmake type-check(backend) andcd web && pnpm exec vp staged(frontend) to appease the lint godsmake lint(backend)