Skip to content

Commit bcbf7dd

Browse files
authored
fix: bundle httpx SOCKS proxy support (#7093)
* fix: bundle httpx SOCKS proxy support * test: tighten SOCKS dependency regression coverage * test: allow SOCKS dependency environment markers * test: broaden SOCKS dependency regex coverage
1 parent fcfd6a9 commit bcbf7dd

3 files changed

Lines changed: 115 additions & 0 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ dependencies = [
2727
"faiss-cpu>=1.12.0",
2828
"filelock>=3.18.0",
2929
"google-genai>=1.56.0",
30+
"httpx[socks]>=0.28.1",
3031
"lark-oapi>=1.4.15",
3132
"lxml-html-clean>=0.4.2",
3233
"mcp>=1.8.0",

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ docstring-parser>=0.16
1717
faiss-cpu>=1.12.0
1818
filelock>=3.18.0
1919
google-genai>=1.56.0
20+
httpx[socks]>=0.28.1
2021
lark-oapi>=1.4.15
2122
lxml-html-clean>=0.4.2
2223
mcp>=1.8.0
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import re
2+
from pathlib import Path
3+
4+
import pytest
5+
import tomllib
6+
7+
PROJECT_ROOT = Path(__file__).resolve().parents[1]
8+
REQUIREMENTS_PATH = PROJECT_ROOT / "requirements.txt"
9+
PYPROJECT_PATH = PROJECT_ROOT / "pyproject.toml"
10+
HTTPX_SOCKS_PATTERN = re.compile(r"^httpx\[socks\](?:\s*[<>=!~][^;]*)?(?:\s*;.*)?$")
11+
12+
13+
def _read_httpx_socks_dependency(entries: list[str]) -> str | None:
14+
for entry in entries:
15+
candidate = entry.strip()
16+
if HTTPX_SOCKS_PATTERN.match(candidate):
17+
return candidate
18+
return None
19+
20+
21+
def _read_requirements() -> list[str]:
22+
entries = []
23+
for line in REQUIREMENTS_PATH.read_text(encoding="utf-8").splitlines():
24+
candidate = line.split("#", 1)[0].strip()
25+
if candidate:
26+
entries.append(candidate)
27+
return entries
28+
29+
30+
def _read_pyproject_dependencies() -> list[str]:
31+
with PYPROJECT_PATH.open("rb") as file:
32+
pyproject = tomllib.load(file)
33+
return pyproject["project"]["dependencies"]
34+
35+
36+
def test_requirements_include_httpx_socks_dependency() -> None:
37+
requirements_dependency = _read_httpx_socks_dependency(_read_requirements())
38+
39+
assert requirements_dependency is not None, (
40+
"Expected httpx[socks] dependency in requirements.txt for SOCKS proxy support"
41+
)
42+
43+
44+
def test_pyproject_declares_httpx_socks_dependency() -> None:
45+
pyproject_dependency = _read_httpx_socks_dependency(_read_pyproject_dependencies())
46+
47+
assert pyproject_dependency is not None, (
48+
"Expected httpx[socks] dependency in pyproject.toml for SOCKS proxy support"
49+
)
50+
51+
52+
def test_httpx_socks_dependency_spec_matches_between_dependency_files() -> None:
53+
requirements_dependency = _read_httpx_socks_dependency(_read_requirements())
54+
pyproject_dependency = _read_httpx_socks_dependency(_read_pyproject_dependencies())
55+
56+
assert requirements_dependency is not None, (
57+
"Expected httpx[socks] dependency in requirements.txt for SOCKS proxy support"
58+
)
59+
assert pyproject_dependency is not None, (
60+
"Expected httpx[socks] dependency in pyproject.toml for SOCKS proxy support"
61+
)
62+
assert requirements_dependency == pyproject_dependency, (
63+
"Expected httpx[socks] dependency spec to match between requirements.txt "
64+
"and pyproject.toml for SOCKS proxy support"
65+
)
66+
67+
68+
@pytest.mark.parametrize(
69+
"entry",
70+
[
71+
"httpx[socks]",
72+
"httpx[socks]==0.27.0",
73+
"httpx[socks]==0.28.1",
74+
"httpx[socks]>=0.27.0,<0.28.0",
75+
"httpx[socks]>=0.27,<0.29",
76+
'httpx[socks]; python_version >= "3.11"',
77+
'httpx[socks]>=0.27.0 ; python_version < "3.13"',
78+
'httpx[socks] ; python_version < "3.13"',
79+
'httpx[socks] >=0.27 ; python_version < "3.13"',
80+
],
81+
)
82+
def test_httpx_socks_pattern_matches_valid_variants(entry: str) -> None:
83+
match = HTTPX_SOCKS_PATTERN.match(entry)
84+
85+
assert match is not None, (
86+
f"Expected httpx[socks] dependency pattern to match valid entry for "
87+
f"SOCKS proxy support: {entry}"
88+
)
89+
assert match.group(0) == entry, (
90+
f"Expected httpx[socks] dependency pattern to fully match valid entry "
91+
f"for SOCKS proxy support: {entry}"
92+
)
93+
94+
95+
@pytest.mark.parametrize(
96+
"entry",
97+
[
98+
"httpx",
99+
"httpx==0.27.0",
100+
"httpx[http2]",
101+
"httpx[socks-extra]",
102+
"httpx [socks]",
103+
"someprefix httpx[socks]",
104+
"httpx[socks] trailing-text",
105+
"httpx[socks] extra ; markers",
106+
"httpx[socks]andmore",
107+
],
108+
)
109+
def test_httpx_socks_pattern_rejects_invalid_variants(entry: str) -> None:
110+
assert HTTPX_SOCKS_PATTERN.match(entry) is None, (
111+
f"Expected httpx[socks] dependency pattern to reject invalid entry for "
112+
f"SOCKS proxy support: {entry}"
113+
)

0 commit comments

Comments
 (0)