-
-
Notifications
You must be signed in to change notification settings - Fork 2k
fix: bundle httpx SOCKS proxy support #7093
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5a7f470
db5eb66
d0431a1
540ff50
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| import re | ||
| from pathlib import Path | ||
|
|
||
| import pytest | ||
| import tomllib | ||
|
|
||
| PROJECT_ROOT = Path(__file__).resolve().parents[1] | ||
| REQUIREMENTS_PATH = PROJECT_ROOT / "requirements.txt" | ||
| PYPROJECT_PATH = PROJECT_ROOT / "pyproject.toml" | ||
| HTTPX_SOCKS_PATTERN = re.compile(r"^httpx\[socks\](?:\s*[<>=!~][^;]*)?(?:\s*;.*)?$") | ||
|
|
||
|
|
||
| def _read_httpx_socks_dependency(entries: list[str]) -> str | None: | ||
| for entry in entries: | ||
| candidate = entry.strip() | ||
| if HTTPX_SOCKS_PATTERN.match(candidate): | ||
| return candidate | ||
| return None | ||
|
|
||
|
|
||
| def _read_requirements() -> list[str]: | ||
| entries = [] | ||
| for line in REQUIREMENTS_PATH.read_text(encoding="utf-8").splitlines(): | ||
| candidate = line.split("#", 1)[0].strip() | ||
| if candidate: | ||
| entries.append(candidate) | ||
| return entries | ||
|
|
||
|
|
||
| def _read_pyproject_dependencies() -> list[str]: | ||
| with PYPROJECT_PATH.open("rb") as file: | ||
| pyproject = tomllib.load(file) | ||
| return pyproject["project"]["dependencies"] | ||
|
Comment on lines
+30
to
+33
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue (testing): The test only checks presence in Right now the tests only assert that each file independently contains |
||
|
|
||
|
|
||
| def test_requirements_include_httpx_socks_dependency() -> None: | ||
| requirements_dependency = _read_httpx_socks_dependency(_read_requirements()) | ||
|
|
||
| assert requirements_dependency is not None, ( | ||
| "Expected httpx[socks] dependency in requirements.txt for SOCKS proxy support" | ||
| ) | ||
|
|
||
|
|
||
| def test_pyproject_declares_httpx_socks_dependency() -> None: | ||
| pyproject_dependency = _read_httpx_socks_dependency(_read_pyproject_dependencies()) | ||
|
|
||
| assert pyproject_dependency is not None, ( | ||
| "Expected httpx[socks] dependency in pyproject.toml for SOCKS proxy support" | ||
| ) | ||
|
|
||
|
|
||
| def test_httpx_socks_dependency_spec_matches_between_dependency_files() -> None: | ||
| requirements_dependency = _read_httpx_socks_dependency(_read_requirements()) | ||
| pyproject_dependency = _read_httpx_socks_dependency(_read_pyproject_dependencies()) | ||
|
|
||
| assert requirements_dependency is not None, ( | ||
| "Expected httpx[socks] dependency in requirements.txt for SOCKS proxy support" | ||
| ) | ||
| assert pyproject_dependency is not None, ( | ||
| "Expected httpx[socks] dependency in pyproject.toml for SOCKS proxy support" | ||
| ) | ||
| assert requirements_dependency == pyproject_dependency, ( | ||
| "Expected httpx[socks] dependency spec to match between requirements.txt " | ||
| "and pyproject.toml for SOCKS proxy support" | ||
| ) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "entry", | ||
| [ | ||
| "httpx[socks]", | ||
| "httpx[socks]==0.27.0", | ||
| "httpx[socks]==0.28.1", | ||
| "httpx[socks]>=0.27.0,<0.28.0", | ||
| "httpx[socks]>=0.27,<0.29", | ||
| 'httpx[socks]; python_version >= "3.11"', | ||
| 'httpx[socks]>=0.27.0 ; python_version < "3.13"', | ||
| 'httpx[socks] ; python_version < "3.13"', | ||
| 'httpx[socks] >=0.27 ; python_version < "3.13"', | ||
| ], | ||
| ) | ||
| def test_httpx_socks_pattern_matches_valid_variants(entry: str) -> None: | ||
| match = HTTPX_SOCKS_PATTERN.match(entry) | ||
|
|
||
| assert match is not None, ( | ||
| f"Expected httpx[socks] dependency pattern to match valid entry for " | ||
| f"SOCKS proxy support: {entry}" | ||
| ) | ||
| assert match.group(0) == entry, ( | ||
| f"Expected httpx[socks] dependency pattern to fully match valid entry " | ||
| f"for SOCKS proxy support: {entry}" | ||
| ) | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "entry", | ||
| [ | ||
| "httpx", | ||
| "httpx==0.27.0", | ||
| "httpx[http2]", | ||
| "httpx[socks-extra]", | ||
| "httpx [socks]", | ||
| "someprefix httpx[socks]", | ||
| "httpx[socks] trailing-text", | ||
| "httpx[socks] extra ; markers", | ||
| "httpx[socks]andmore", | ||
| ], | ||
| ) | ||
| def test_httpx_socks_pattern_rejects_invalid_variants(entry: str) -> None: | ||
| assert HTTPX_SOCKS_PATTERN.match(entry) is None, ( | ||
| f"Expected httpx[socks] dependency pattern to reject invalid entry for " | ||
| f"SOCKS proxy support: {entry}" | ||
| ) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (testing): Add negative tests to ensure the pattern does not match non-SOCKS httpx dependencies or malformed entries.
Currently we only verify that
HTTPX_SOCKS_PATTERNmatches a validhttpx[socks]requirement. Please also add assertions that it does not match invalid cases such ashttpx,httpx[http2],httpx[socks-extra], and entries with extra leading/trailing text, so future regex changes that are too broad are caught by tests.