diff --git a/README.md b/README.md index 1097ba2..bcdc250 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,9 @@ key (`host:port:user:pass`, or `host:port` auth-less; the port is normalized so differing only by password are distinct slots. `burn` on a proxy not in the pool raises `ValueError`; `restore` on a proxy not in the pool logs a warning and no-ops (matching `remove`'s contract, as of v0.3.0 — previously it silently did nothing with no signal). +A **portless** url (`http://user:pass@host`, no `:port`) parses fine via `to_proxy()`, +but keying it (`canonical_key`/`.key()`/`burn`/`add`/`remove`) raises `ValueError` +naming the missing port — a proxy needs a port to have a canonical identity. ### Cooldown @@ -209,6 +212,17 @@ await reset("https://provider/reset-url") # rotate upstream ip ## Changelog +### v0.3.2 + +- **Portless proxy url now fails loud and legible.** `canonical_key`/`.key()` + (and therefore `burn`/`add`/`remove`) on a proxy url with no `:port` + (`http://user:pass@host`) used to raise a bare `ValueError("invalid literal + for int() with base 10: ''")` from `normalize_port('')` — an unrelated `int()` + error that broke `burn()`'s documented "raises ValueError naming the key if + not in pool" contract. `normalize_port` now raises `ValueError("missing port: + ...")` naming the problem instead. `to_proxy()` on a portless url still + succeeds (construction tolerates a missing port); only keying it raises. + ### v0.3.1 - **Docs-only de-bloat pass.** Compressed module/internal docstrings and comments, diff --git a/pyproject.toml b/pyproject.toml index 1c77481..2a8fb57 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "aioproxies" -version = "0.3.1" +version = "0.3.2" description = "proxy parsing, formatting, health, and pool management for aiohttp/aioweb, camoufox, and socks5" requires-python = ">=3.10" dependencies = [] diff --git a/src/aioproxies/proxy.py b/src/aioproxies/proxy.py index 8b21ec6..7eb3588 100644 --- a/src/aioproxies/proxy.py +++ b/src/aioproxies/proxy.py @@ -19,9 +19,12 @@ SCHEME_SOCKS5 = "socks5" def normalize_port(port: Union[str, int]) -> str: """canonical port string: parsed to int, rendered without zero-padding - keeps host:080 and host:80 as one canonical key. raises ValueError on a - non-integer port rather than silently keying it as-is. + keeps host:080 and host:80 as one canonical key. raises ValueError naming the + missing port if empty/None (e.g. a portless proxy url), or on a non-integer + port, rather than silently keying it as-is. """ + if port is None or port == "": + raise ValueError("missing port: proxy url or spec has no port") return str(int(port))