Skip to content

chore: migrate httpx to httpx2 (PY-09)#38

Draft
KhaledSalhab-Develeap wants to merge 6 commits into
mainfrom
chore/0cf5e1-httpx2-migration
Draft

chore: migrate httpx to httpx2 (PY-09)#38
KhaledSalhab-Develeap wants to merge 6 commits into
mainfrom
chore/0cf5e1-httpx2-migration

Conversation

@KhaledSalhab-Develeap

Copy link
Copy Markdown
Collaborator

Summary

Migrates the project's HTTP client from httpx (0.x) to httpx2 (2.x), the successor library that Pydantic and other projects have adopted as the 2026 default. This is a mechanical dependency swap: the API surface is identical so all calling code is unchanged.

What changed

File Change
pyproject.toml httpx>=0.27,<1.0 replaced with httpx2>=2.4,<3.0
uv.lock Re-locked with httpx2 and its httpcore2 transitive dependency
src/hyperping/client.py import httpx2 as httpx
src/hyperping/_async_client.py import httpx2 as httpx
src/hyperping/_mcp_transport.py import httpx2 as httpx
src/hyperping/_async_mcp_transport.py import httpx2 as httpx
tests/unit/conftest.py Extend respx HTTPCoreMocker with httpcore2 targets
tests/unit/test_async_client.py Switch to import httpx2 as httpx (no respx usage)
tests/unit/test_client_coverage.py Add import httpcore2; swap side-effect exceptions

Why this shape

httpx2 uses httpcore2 instead of httpcore internally. The test mocking library (respx) patches httpcore by default; extending its HTTPCoreMocker.targets with the httpcore2 equivalents in conftest is the minimal shim to keep the existing @respx.mock pattern working without rewriting tests.

The alias import httpx2 as httpx ensures zero diffs in calling code: the library surface is identical so type annotations, exception catches, and client construction all remain unchanged.

Verification matrix

Check Result
pytest tests/unit/ --ignore=test_otel.py 563 passed, 0 failed
Coverage 93.91% (above 85% threshold)
ruff check src/ tests/unit/ All checks passed
mypy src/hyperping/ Success: no issues found in 39 source files
uv sync --extra dev Resolves cleanly with httpx2 2.4.0 + httpcore2 2.4.0

Acceptance criteria

  • httpx dependency replaced with httpx2>=2.4,<3.0 in pyproject.toml
  • All client construction sites updated (4 files)
  • Async streaming, retry, and circuit-breaker integrations verified via test suite
  • httpx2 version pinned explicitly in uv.lock (2.4.0)
  • CI: existing test suite passes at 563 tests

KhaledSalhab-Develeap and others added 5 commits June 13, 2026 04:45
…t production API (#9606db)

- Fix Integration crash: alias was 'type' but API returns 'channel'; rename alias
  to 'channel', keep Python attribute as integration_type for compat
- Remove phantom active field from Integration (API never returns it)
- Promote Integration fields: created_by, created_at, region, metadata
- Define EscalationStep sub-model with uuid, wait_before, channels, temp_id
- Promote EscalationPolicy fields: created_by, created_at, grouped_alerts_window,
  grouped_alerts_enabled, monitor_count; type steps as list[EscalationStep]
- Add sso_picture_url to TeamMember
- Export EscalationStep from hyperping.models and hyperping top-level
…ationPolicy/TeamMember (#9606db)

- Sync test: use channel instead of type in Integration mocks, assert new fields
- Sync test: enrich EscalationPolicy mocks with steps/createdAt/monitorCount, add EscalationStep assertions
- Sync test: add ssoPictureUrl to TeamMember mock, assert sso_picture_url
- Async test: mirror all sync mock updates and assertions
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Adding EscalationStep to the oncall_models import pushed the line past
the 100-character limit. Split it across lines using parentheses so
both E501 and I001 stay clean.
Replace httpx>=0.27,<1.0 with httpx2>=2.4,<3.0 in project dependencies.
Update all four client construction sites (client.py, _async_client.py,
_mcp_transport.py, _async_mcp_transport.py) to import httpx2 with an httpx
alias so the rest of the code is unchanged.

Since httpx2 uses httpcore2 instead of httpcore, extend respx's default
HTTPCoreMocker with httpcore2 targets in conftest so @respx.mock continues
to intercept test requests.

Two test adjustments for type compatibility:
- test_async_client.py: switch to httpx2 (no respx mock usage, direct
  _client.request patching); MagicMock(spec=httpx2.Response) and
  httpx2.ConnectError side effects now match the client exception handlers.
- test_client_coverage.py: keep httpx for respx return values; replace
  httpx.ConnectError/TimeoutException side effects with httpcore2 equivalents
  so httpx2 exception mapper converts them to types the client catches.
@ksalhab89

Copy link
Copy Markdown

Reviewer context (not a merge request):

PY-09 httpx2 migration plus on-call/integration model enrichment: adds EscalationStep, types EscalationPolicy.steps as list[EscalationStep], and adds fields to Integration, EscalationPolicy, TeamMember.

Where to focus review: models/_oncall_models.py and _integration_models.py. Note the breaking-ish change in Integration.integration_type: alias moves from "type" to "channel", so payloads keyed "type" will no longer populate it. Verify Hyperping's real list/get responses use channel (tests assert channel: "teams"). EscalationPolicy.steps changes from list[dict[str, Any]] to typed models; any caller treating steps as plain dicts breaks. Confirm the conftest.py httpcore2 respx shim and httpcore2.ConnectTimeout/ConnectError substitutions in test_client_coverage.py.

Risks / verify: The type->channel alias change is the key backward-compat risk; confirm against the live API. frozen=True models with extra="allow". uv.lock bumps package version to 1.8.0 and adds httpx2/httpcore2 2.4.0.

CI status: No checks triggered (targets main, no run recorded). Not red.

Notes: Another httpx2 migration (overlaps #39/#40/#44). Consolidate the migration into a single PR to avoid repeated lockfile churn.

Resolves the uv.lock conflict by regenerating the lockfile against the merged
pyproject (httpx2 dependency plus the hyp CLI / typer extras now on main).
No source conflicts.
@ksalhab89

Copy link
Copy Markdown

Update (conflict resolution + merge order): Merged main in and regenerated uv.lock; this PR is now MERGEABLE (was CONFLICTING). The only conflict was the lockfile.

This is the httpx2 migration base. Recommended to merge first among the migration PRs.

Important: #39 and #40 each independently carry the same httpx2 swap (not stacked on this PR), so merging more than one lineage will conflict heavily. Pick one: either merge this (#38) for httpx2 alone, or merge #40 which bundles httpx2 + streaming + full OTel. Do not merge both #38 and #40.

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.

2 participants