Skip to content

[HTTPXodus] migrate httpx to httpx2 (hard switch) - #7040

Open
ProgrammerPlus1998 wants to merge 3 commits into
reflex-dev:mainfrom
ProgrammerPlus1998:httpxodus/httpx2-migration
Open

[HTTPXodus] migrate httpx to httpx2 (hard switch)#7040
ProgrammerPlus1998 wants to merge 3 commits into
reflex-dev:mainfrom
ProgrammerPlus1998:httpxodus/httpx2-migration

Conversation

@ProgrammerPlus1998

@ProgrammerPlus1998 ProgrammerPlus1998 commented Sep 3, 2026

Copy link
Copy Markdown

Closes #7034

🏷️ Part of HTTPXodus — a community effort to help major Python projects plan their path off the stalled httpx stable line onto httpx2, the actively maintained fork by Pydantic Services.

What this PR does

Complete hard switch of the main reflex package from httpx to httpx2:

  • Direct import httpx2 everywhere — no try/except ImportError fallback, no import httpx2 as httpx aliasing
  • Removes the httpx runtime dependency; httpx2>=2.12.0 unconditional (requires-python is already >=3.10, so no version-marker needed)
  • httpx.Client, httpx.AsyncClient, httpx.Limits, httpx.HTTPTransport, httpx.Proxy, httpx.HTTPErrorhttpx2.X
  • from httpx._utils import get_environment_proxiesfrom httpx2._utils import get_environment_proxies (httpx2 ships the same helper)

Diff summary

12 files (commit e71e2e5):

Area Change
reflex/utils/ (net, telemetry, registry, js_runtimes, templates, frontend_skeleton) import httpx2 as httpximport httpx2; all usages renamed
reflex/custom_components/custom_components.py Same
tests/units/test_telemetry.py, tests/units/utils/test_utils.py, tests/test_node_version.py Remove the last two ModuleNotFoundError fallbacks; patch targets and mock dependency data updated
pyproject.toml Drop httpx >=0.26,<1.0; httpx2 >=2.12.0 without version marker
uv.lock Record the httpx2 swap; also repairs a corrupt duplicate ty entry (0.0.69 pointing at truststore artifacts) that current uv releases refuse to parse

Scope

packages/reflex-hosting-cli (a separate distribution that pins httpx <1.0) and packages/reflex-site-shared are unchanged — they keep httpx for now, so httpx remains installed transitively via reflex-hosting-cli. Migrating the hosting CLI (50+ lazy imports in hosting.py alone) is a natural follow-up PR.

Test results

  • Full pytest tests/units: 7997 passed, 18 skipped, in a fresh venv installed from this branch's uv.lock (uv sync --frozen) with httpx2 2.12.0
  • The 163 failures are all in tests/units/reflex_cli/ (the hosting-CLI sub-package this PR deliberately does not touch): they fail with "Reflex version 0.0.0.post2.dev0 is not compatible with reflex-hosting-cli", an artifact of the local editable install having no git tags (uv-dynamic-versioning fallback), not of this change

Notes for reviewer

  • ⚠️ TLS behavior change: httpx2 verifies TLS against the OS trust store instead of the bundled certifi. Self-hosted Reflex deployments behind corporate proxies or in minimal containers that relied on certifi's CA bundle may need SSL_CERT_FILE / SSL_CERT_DIR after the switch. Worth a line in the changelog.
  • The uv.lock repair (corrupt ty entry) is included here because the dependency swap requires re-locking anyway; happy to split it out if you prefer.

Happy to revise per review — and equally happy to close this PR if the maintainers would rather wait for httpx 1.0 stable. 🙏

@ProgrammerPlus1998
ProgrammerPlus1998 requested a review from a team as a code owner September 3, 2026 04:14
@greptile-apps

greptile-apps Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 3/5

The PR is not yet safe to merge because the committed lockfile disagrees with the project manifest, and the required user-facing news fragment is missing.

Findings

  1. P1 Lockfile Adds Undeclared Extra
  2. P2 Required News Fragment Missing

Summary

  • Replaces direct httpx usage with httpx2.
  • Updates the shared client, proxy transports, and environment-proxy helper.
  • Changes the runtime dependency to httpx2>=2.12.0.
  • Updates tests and the uv lockfile for the new package.
  • The refreshed lockfile currently contains root-package metadata absent from pyproject.toml, and the user-facing migration lacks the required news fragment.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 12 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread pyproject.toml Outdated
Comment thread reflex/utils/js_runtimes.py Outdated
@codspeed-hq

codspeed-hq Bot commented Sep 3, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 4.63%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
✅ 31 untouched benchmarks
⏩ 8 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
test_collect_imports[_complicated_page] 1.6 ms 1.6 ms +4.63%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing ProgrammerPlus1998:httpxodus/httpx2-migration (b965d6f) with main (3e3732d)

Open in CodSpeed

Footnotes

  1. 8 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

Use the actively maintained httpx2 fork (Pydantic Services) when available,
falling back to httpx. All 7 internal call sites are CLI/framework tooling
(no AsyncClient, no public API exposure). The private import in net.py
(get_environment_proxies) is also dual-bound because httpx2 ships an
equivalent helper.

Refs: reflex-dev#7034
…x dual-import

Signed-off-by: xic <xiechen@cls.cn>
@ProgrammerPlus1998
ProgrammerPlus1998 force-pushed the httpxodus/httpx2-migration branch from b965d6f to 471b42b Compare September 4, 2026 02:26
@FarhanAliRaza FarhanAliRaza changed the title [HTTPXodus] migrate httpx to httpx2 (dual import) migrate httpx to httpx2 (dual import) Sep 4, 2026

@masenf masenf left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i dont understand how the "dual import" thing really helps us here.

if we're adding httpx2 to the framework deps, it will always be installed and thus we should just import httpx2.

if downstream code was depending on httpx and not declaring it as their own dependency, then they will be broken, but i'm okay with that. downstream should not be assuming that the framework dependencies can just be used because they happen to be there.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 7 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="reflex/utils/net.py">

<violation number="1" location="reflex/utils/net.py:159">
P3: The comment block just above this import still describes behavior removed by this change: it says the code "fall[s] back to real httpx on Python 3.8/3.9" and that `httpx2` is "a union of the two modules" via a try/except. This file now hard-imports httpx2, and `pyproject.toml` declares `httpx2 >=2.0` for the full supported range (`requires-python = ">=3.10"`), so there is no fallback and no union. The stale text and the `# type: ignore` suppressions (added only to silence the union inference) will mislead future maintainers. Update the comments to state that httpx2 is the sole HTTP client, and drop the now-unneeded `# type: ignore` suppressions on the Client/HTTPTransport/Proxy calls now that `httpx2` is no longer a union.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread reflex/utils/net.py
# infer a union of `httpx2.HTTPTransport | httpx.HTTPTransport` —
# that union is not assignable to `Client(mounts=...)` because the
# two transport classes are unrelated.
import httpx2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The comment block just above this import still describes behavior removed by this change: it says the code "fall[s] back to real httpx on Python 3.8/3.9" and that httpx2 is "a union of the two modules" via a try/except. This file now hard-imports httpx2, and pyproject.toml declares httpx2 >=2.0 for the full supported range (requires-python = ">=3.10"), so there is no fallback and no union. The stale text and the # type: ignore suppressions (added only to silence the union inference) will mislead future maintainers. Update the comments to state that httpx2 is the sole HTTP client, and drop the now-unneeded # type: ignore suppressions on the Client/HTTPTransport/Proxy calls now that httpx2 is no longer a union.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At reflex/utils/net.py, line 159:

<comment>The comment block just above this import still describes behavior removed by this change: it says the code "fall[s] back to real httpx on Python 3.8/3.9" and that `httpx2` is "a union of the two modules" via a try/except. This file now hard-imports httpx2, and `pyproject.toml` declares `httpx2 >=2.0` for the full supported range (`requires-python = ">=3.10"`), so there is no fallback and no union. The stale text and the `# type: ignore` suppressions (added only to silence the union inference) will mislead future maintainers. Update the comments to state that httpx2 is the sole HTTP client, and drop the now-unneeded `# type: ignore` suppressions on the Client/HTTPTransport/Proxy calls now that `httpx2` is no longer a union.</comment>

<file context>
@@ -165,12 +156,8 @@ def _httpx_client():
-    except ModuleNotFoundError:
-        import httpx as httpx2  # noqa: F401 — local name `httpx2` bound to the real httpx
-        from httpx._utils import get_environment_proxies  # noqa: F811
+    import httpx2
+    from httpx2._utils import get_environment_proxies
 
</file context>

@ProgrammerPlus1998 ProgrammerPlus1998 changed the title migrate httpx to httpx2 (dual import) migrate httpx to httpx2 Sep 8, 2026
Use direct 'import httpx2' across the main package: drop the
'import httpx2 as httpx' aliasing and the two remaining
ModuleNotFoundError fallbacks in tests. Remove the httpx runtime
dependency; httpx2>=2.12.0 is unconditional (requires-python is
already >=3.10). Repair uv.lock: replace a corrupt duplicate 'ty'
entry (0.0.69 pointing at truststore artifacts, rejected by uv) and
record the httpx2 swap.

reflex-hosting-cli (separate distribution, pins httpx <1.0) and
reflex-site-shared keep httpx for now; httpx remains installed
transitively via reflex-hosting-cli.

Refs: reflex-dev#7034
@ProgrammerPlus1998
ProgrammerPlus1998 force-pushed the httpxodus/httpx2-migration branch from fb48705 to e71e2e5 Compare September 9, 2026 08:49
@ProgrammerPlus1998 ProgrammerPlus1998 changed the title migrate httpx to httpx2 [HTTPXodus] migrate httpx to httpx2 (hard switch) Sep 9, 2026
Comment thread uv.lock
Comment on lines +3804 to +3808
testing = [
{ name = "psutil" },
{ name = "selenium" },
{ name = "uvicorn" },
]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Lockfile Adds Undeclared Extra

The regenerated lockfile adds a testing extra with psutil, selenium, and uvicorn, but pyproject.toml defines only the db and pydantic extras. This leaves the lockfile out of sync with the project manifest and can cause checked or frozen dependency workflows to fail. Please regenerate it strictly from the committed manifest without the unrelated extra.

Comment thread pyproject.toml
"click >=8.2",
"granian[reload] >=2.7.4",
"httpx >=0.26,<1.0",
"httpx2 >=2.12.0",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Required News Fragment Missing

This hard switch changes the runtime HTTP dependency and TLS trust behavior for downstream users, but it does not add a root-package news fragment. The repository requires user-facing changes to include a news/7040.<type>.md entry explaining what changed and what it means for users, so this requirement must be satisfied before merging.

Context Used: CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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.

[HTTPXodus] Consider migrating from httpx to httpx2 (the actively maintained fork)

2 participants