Skip to content

Refactor: deduplicate request/response handling in entity classes - #104

Open
kir1903 wants to merge 5 commits into
evrone:masterfrom
kir1903:refactor/entities-deduplication
Open

Refactor: deduplicate request/response handling in entity classes#104
kir1903 wants to merge 5 commits into
evrone:masterfrom
kir1903:refactor/entities-deduplication

Conversation

@kir1903

@kir1903 kir1903 commented Sep 9, 2026

Copy link
Copy Markdown

Summary

  • Extract the repeated "call httpx client -> raise_for_status -> response.json() -> Schema.model_validate()" block (~25 occurrences across Workspace, CurrentUser, ReportTimeEntry) into shared _request, _request_and_validate, _request_and_validate_list and _request_and_check_success helpers on the base ApiWrapper class.
  • Extract the repeated payload_schema.model_dump(mode="json", exclude_none=True[, exclude_unset=True]) call (13 occurrences) into a dump_payload() helper in schemas/base.py.
  • Pure structural refactor: no behavior change, all existing tests pass unmodified.

Principles applied

  • Extract Method / Pull Up Method — duplicated logic moved into the existing common base class (ApiWrapper), which every entity class already inherits from.
  • DRY — both identified duplications (request+validate boilerplate, payload serialization) removed.

Test plan

  • poetry run pytest -m "not integration" — 191 passed, coverage 97.85% (threshold 95%)
  • Added tests/test_api.py (4 tests) covering the new ApiWrapper helpers (success + error paths) via respx
  • Added tests/test_schemas_base.py (4 tests) covering dump_payload() (exclude_none, exclude_unset semantics)
  • poetry run ruff check clean on all touched files
  • Existing entity tests (test_workspace.py, test_user.py, test_project.py, test_time_entry.py, test_report_time_entry.py) pass unmodified

Workspace, CurrentUser and ReportTimeEntry each repeated the same
"call httpx client -> raise_for_status -> response.json() -> validate
with a Pydantic schema" block roughly 25 times, both for single
objects, lists and boolean success responses.

Add _request, _request_and_validate, _request_and_validate_list and
_request_and_check_success to the shared ApiWrapper base class so
that duplication can be removed from the entity classes.
Replace repeated client-call/raise_for_status/json/model_validate
blocks in Workspace's 12 methods with calls to the new
_request_and_validate / _request_and_validate_list /
_request_and_check_success helpers. No behavior change.
Same mechanical deduplication as the Workspace entity: replace
repeated client-call/raise_for_status/json/model_validate blocks in
CurrentUser's 11 methods with the shared helpers. get_current_time_entry
keeps its manual json() call since it needs to special-case an empty
body into None. No behavior change.
Same mechanical deduplication as Workspace and CurrentUser, applied
to ReportTimeEntry.search. Pagination logic (first_row_number
calculation) is unchanged. No behavior change.
payload_schema.model_dump(mode="json", exclude_none=True[, exclude_unset=True])
was repeated 13 times across Workspace, CurrentUser and ReportTimeEntry to
turn a validated Pydantic schema into query params / a request body.

Add dump_payload() to schemas/base.py and use it at all matching call
sites. Calls with a different shape (model_dump_json(), or
BulkEditMethodParams' plain model_dump(mode="json") without
exclude_none) are intentionally left as-is since they are not the
same pattern. No behavior change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant