Skip to content

feat!: migrate to httpx2 and consolidate the unshipped 0.1.2 into 0.2.0 - #11

Merged
yudelevi merged 3 commits into
developmentfrom
feat/httpx2-migration
Aug 21, 2026
Merged

feat!: migrate to httpx2 and consolidate the unshipped 0.1.2 into 0.2.0#11
yudelevi merged 3 commits into
developmentfrom
feat/httpx2-migration

Conversation

@yudelevi

@yudelevi yudelevi commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Why

httpx upstream has seen limited activity, and Pydantic has picked up stewardship as httpx2 specifically to keep security updates flowing for a library sitting in the critical path of production traffic. This SDK is that critical path for its users, so it follows the maintained fork.

While here, this also fixes a release that got stuck: 0.1.2 was written into the changelog and version files on 2026-08-19 but never tagged or published. PyPI still serves 0.1.1, and both cross-package pins referenced a 0.1.2 that does not exist on the index — meaning pip install discolike-cli could not resolve today.

What

httpx → httpx2 (005d083) — mechanical rename across the SDK, testkit, tests, scripts/check_contract.py, and the README. Every symbol in use (Response, Request, QueryParams, MockTransport, Client, AsyncClient, Timeout, USE_CLIENT_DEFAULT, TransportError, ConnectError) exists unchanged in httpx2, so no logic moved. Dependency floor is httpx2>=2.9.

Release consolidation (9bc79a6) — the unshipped 0.1.2 section folds into 0.2.0 alongside the pending work. 0.2.0 rather than 0.1.3 because that section already removed companies.metrics/history and changed four company endpoints to return lists, and httpx2 breaks the public client types on top of that.

Exact sibling pins (47a315c) — discolike-cli now requires discolike==0.2.0 and the discolike[cli] extra requires discolike-cli==0.2.0, replacing the previous bare >= floor. The CLI is the SDK's front end rather than an independent consumer, so the installed pair is always the tested pair.

Breaking changes

httpx types are part of the public surface, so callers must update:

Before After
import httpx import httpx2
Client(http_client=httpx.Client(...)) Client(http_client=httpx2.Client(...))
client.with_options(timeout=httpx.Timeout(...)) client.with_options(timeout=httpx2.Timeout(...))
testkit Handler = Callable[[httpx.Request], httpx.Response] same, with httpx2

Behavior change worth flagging: httpx2 verifies TLS against the operating system trust store via truststore instead of the bundled certifi roots. No code change on our side, but users on hosts with an incomplete or custom system trust store may see verification failures that certifi previously masked.

Testing

  • 315 tests pass; ruff check and ruff format --check clean; ty reports the same 3 pre-existing examples/ diagnostics as development, no new ones.
  • The suite drives everything through MockTransport, so it proves API compatibility but never opens a socket. Verified the real wire path separately: a live HTTPS request to api.discolike.com completes the handshake and round trip under httpx2's truststore-based verification.

Release notes

Nothing is tagged or published by this PR. Merging leaves development holding a complete 0.2.0. When it ships, both packages must be published together — the exact pins make discolike[cli] unsatisfiable in the window between the two uploads.

Greptile Summary

The PR migrates the SDK and test infrastructure from httpx to httpx2 and consolidates the pending release as 0.2.0.

  • Replaces httpx imports, public types, transport exceptions, clients, and test mocks with httpx2 equivalents.
  • Pins the SDK and CLI packages to matching 0.2.0 sibling releases.
  • Updates release metadata, documentation, changelog entries, and the workspace lockfile.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete unacknowledged defects identified in the changed code.

The migration consistently updates production, testkit, tests, tooling, dependency metadata, and lockfile references, while the exact-pin publication window is explicitly documented and no incompatible httpx2 behavior was established.

Important Files Changed

Filename Overview
packages/discolike/src/discolike/_transport.py Mechanically migrates sync and async transport clients, timeout handling, and retryable exceptions to httpx2 without changing transport logic.
packages/discolike/src/discolike/_client.py Updates public custom-client and timeout annotations to httpx2 while preserving client construction and resource attachment behavior.
packages/discolike/pyproject.toml Replaces the runtime HTTP dependency with httpx2 and exactly pins the optional CLI sibling to 0.2.0.
packages/discolike-cli/pyproject.toml Bumps the CLI to 0.2.0 and exactly pins its SDK dependency to the matching release.
packages/discolike-testkit/src/discolike_testkit/plugin.py Migrates shared sync and async mock-client fixtures to httpx2.
scripts/check_contract.py Migrates the live OpenAPI request to httpx2; local specification loading and contract comparison logic remain unchanged.
uv.lock Regenerates the workspace resolution around httpx2, httpcore2, truststore, and the updated package versions.

Reviews (1): Last reviewed commit: "build: pin the CLI and SDK to each other..." | Re-trigger Greptile

httpx upstream is low-activity; Pydantic maintains httpx2 as its
continuation and ships security fixes for it. This library sits in the
critical path of user requests, so it follows the maintained fork.

Breaking: httpx types are part of the public surface (http_client=,
with_options(timeout=), the testkit Handler alias), so callers must swap
`import httpx` for `import httpx2`. httpx2 also verifies TLS against the
OS trust store via truststore rather than bundled certifi roots.
0.1.2 was written into the changelog and version files on 2026-08-19 but
never tagged or published — PyPI still serves 0.1.1. Since no user ever
saw a 0.1.2, its entries fold into the release that actually ships rather
than shipping two versions on one day.

0.2.0 rather than 0.1.3: the unshipped section already dropped
companies.metrics/history and changed four company endpoints to return
lists, and the httpx2 move breaks the public client types on top of that.

Also repoints the cross-package pins (discolike-cli -> discolike, the
discolike[cli] extra), which referenced the 0.1.2 that never existed on
the index and so could not resolve.
The CLI is not an independent consumer of the SDK — it is the SDK's
command-line front end, released from this repo in lockstep and only ever
tested against its own generation. A range pin invites combinations that
never ran together in CI; an exact pin means the pair a user installs is
the pair that was tested.

Consequence: both packages ship on every release, including one whose own
code did not change. Publishing them together also matters, since
discolike[cli] is unsatisfiable in the window between the two uploads.
@yudelevi
yudelevi merged commit b4e5a5f into development Aug 21, 2026
8 checks passed
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