Context
Flagged in PR #8 review (claude[bot] 2026-04-11):
client.py and async_client.py carry ~380 lines of duplicated business logic each (validation, body construction, docstrings). The module-level comment ("keep both in sync") is honest but brittle. Consider whether a shared mixin or a thin async wrapper pattern could reduce the surface area for drift in a follow-up — not a blocker for this PR since the sync/async mirror tests provide a safety net.
Options
- Shared mixin — extract validation, body construction, and docstrings into a base class. Both
QURLClient and AsyncQURLClient inherit it and only implement the HTTP plumbing (_raw_request).
- Thin async wrapper — keep the sync client as the primary implementation, wrap it with
asyncio.to_thread or a similar pattern. Downside: loses native async httpx benefits.
- Code generation — generate one client from the other via a build-time script. Keeps native async but adds a build step.
Status quo safety net
The sync/async mirror tests in test_client.py catch drift: every new method/edge case gets both a sync and async test. This is sufficient for now but doesn't scale well as the API surface grows.
Not a blocker for PR #8
Reviewer explicitly labeled this "not a blocker… consider in a follow-up." The mirror tests provide adequate safety for the current scope.
Context
Flagged in PR #8 review (claude[bot] 2026-04-11):
Options
QURLClientandAsyncQURLClientinherit it and only implement the HTTP plumbing (_raw_request).asyncio.to_threador a similar pattern. Downside: loses native async httpx benefits.Status quo safety net
The sync/async mirror tests in
test_client.pycatch drift: every new method/edge case gets both a sync and async test. This is sufficient for now but doesn't scale well as the API surface grows.Not a blocker for PR #8
Reviewer explicitly labeled this "not a blocker… consider in a follow-up." The mirror tests provide adequate safety for the current scope.