Skip to main content

proxylib

PyPI version Python versions License: MIT Docs

Platform-agnostic proxy configuration for Python: detect the system/environment proxy settings, evaluate PAC (Proxy Auto-Config) files — including WPAD auto-discovery — and wire the result straight into requests or urllib.

Zero required runtime dependencies; a couple of optional extras unlock more (see below).

Features

  • Proxy string parsing — PROXY host:port; DIRECT-style PAC strings, scheme://host:port URLs, and env-var-style values, all normalized into a common Proxy type.
  • System proxy detection — Windows (via the WinHTTP API), macOS (scutil --proxy), and Linux (env vars, plus best-effort libproxy, GNOME, MATE, KDE, and NetworkManager checks — tried in that order, first match wins). system_proxy() respects each OS/desktop's own auto-detect (WPAD) signal — "Automatically detect settings" on Windows, "Auto Proxy Discovery" on macOS, mode auto with a blank Configuration URL on GNOME/MATE, ProxyType=3 in KDE's kioslaverc, or NetworkManager's proxy.method=auto with no PAC set — and tries WPAD itself first, in that platform's own precedence order (auto-detect → PAC script → manual proxy → DIRECT). NetworkManager is read via nmcli if installed, else dbus-send directly. LibProxyMap (libproxy's own resolution, called via ctypes bindings to its C API — no subprocess) is also available as a standalone ProxyMap you can use directly on any platform.
  • Env var proxy config — HTTP_PROXY/HTTPS_PROXY/NO_PROXY (and lowercase variants), with correct exact/subdomain NO_PROXY matching, plus CIDR entries, <local>, and * (bypass everything; curl and requests honour it only as the whole value, proxylib anywhere in the list).
  • PAC support — the full Netscape PAC utility-function set (including dateRange/timeRange) plus the common Microsoft *Ex extensions, runnable either as real JavaScript through a pluggable engine (dukpy or quickjs, picked via PROXYLIB_JS_ENGINE or preferring quickjs if installed) or by subclassing in Python.
  • WPAD discovery — DNS + HTTP wpad.<domain>/wpad.dat lookup. Used directly by system_proxy() on any platform/desktop whose own auto-detect setting is on, and as a generic last-resort fallback in auto_proxy() when nothing else is configured. Results (including "no WPAD server here") are cached for 5 minutes so repeated lookups don't re-probe the network, and DNS resolution fails fast on a hanging lookup.
  • requests integration — a ProxyMapAdapter Transport Adapter that resolves the proxy from the real request URL (not just scheme+host).
  • urllib.request integration — ProxyMapHandler, the same idea as ProxyMapAdapter but for the standard library's opener/handler system.
  • Global patching — proxylib.patch(proxymap) wires an active ProxyMap into newly created requests.Sessions and a global urllib opener, without mounting an adapter by hand; proxylib.unpatch() undoes it, and any ProxyMap also works directly as a context manager (with proxymap:).
  • Decorators & composition — ChainProxyMap for sequential fallback across multiple ProxyMaps, and ConfigurableProxyMap for opt-in caching, active reachability probing (with a circuit breaker for dead proxies), round-robin selection, browser-style HTTPS privacy stripping, and local-address bypass.

Installation

pip install proxylib

Optional extras:

Extra Adds Needed for
proxylib[jspac] dukpy Executing PAC files as JavaScript — "any working engine" meta-extra
proxylib[dukpy] dukpy The dukpy JS engine specifically
proxylib[quickjs] quickjs-ng (Python ≥3.10) / quickjs (Python 3.9) The quickjs JS engine specifically (no dependency on dukpy)
proxylib[ifaddr] ifaddr Accurate local network interface/prefix enumeration (used by NO_PROXY <local>)

Without a JS engine installed, PAC files are still fetched and validated, but evaluate to DIRECT (with a warning) since there's no engine to run them. With more than one installed, quickjs is preferred by default; set PROXYLIB_JS_ENGINE=dukpy (or a comma-separated priority list) to change that.

Quick start

Auto-detect the system proxy and use it with requests

import requests
from proxylib import auto_proxy, ProxyMapAdapter

proxymap = auto_proxy()  # OS settings -> env vars -> WPAD discovery -> DIRECT

session = requests.Session()
adapter = ProxyMapAdapter(proxymap)
session.mount("http://", adapter)
session.mount("https://", adapter)

response = session.get("https://example.com")

ProxyMapAdapter is the recommended integration: it hooks HTTPAdapter.send(), so it sees the real request URL (scheme, host and path) — exactly what a PAC file's FindProxyForURL is meant to receive.

When you don't need that fidelity (no PAC path rules), ProxyDict is the simpler option — a drop-in for any plain proxies dict:

from proxylib import auto_proxy, ProxyDict

requests.get("https://example.com", proxies=ProxyDict(auto_proxy()))

...or with plain urllib.request

import urllib.request
from proxylib import auto_proxy, ProxyMapHandler

proxymap = auto_proxy()
opener = urllib.request.build_opener(ProxyMapHandler(proxymap))
opener.open("https://example.com")

# or, to affect every urllib.request.urlopen() call process-wide:
urllib.request.install_opener(opener)

ProxyMapHandler subclasses urllib.request.ProxyHandler but resolves per-request from the ProxyMap instead of a static {scheme: proxy_url} dict, for the same reason ProxyMapAdapter exists for requests.

...or patch every new requests.Session/urllib opener at once

import proxylib

with proxylib.auto_proxy():  # patch() on __enter__, unpatch() on __exit__
    requests.get("https://example.com")  # any new Session picks up the active proxy

Outside a with block, call proxylib.patch(proxymap)/proxylib.unpatch() directly, or pass targets=["requests"]/["urllib"] to patch just one. Sessions created before patch() are untouched.

From environment variables

from proxylib import EnvProxyConfig

proxymap = EnvProxyConfig.from_env()  # HTTP_PROXY / HTTPS_PROXY / NO_PROXY
proxymap["https://example.com"]  # -> [Proxy(...)] or [None] for DIRECT

A fixed proxy, or DIRECT

from proxylib import SimpleProxyMap

proxymap = SimpleProxyMap("http://user:pass@proxy.example.com:8080")
direct = SimpleProxyMap("DIRECT")

Loading a PAC file directly

from proxylib import load_pac

proxymap = load_pac("https://example.com/proxy.pac")
proxymap = load_pac("file:./proxy.pac")
proxymap["https://example.com/"]

ProxyMap(source) is a small factory that picks the right implementation for you: a bare scheme://host:port string builds a SimpleProxyMap, while anything that looks like a PAC file/URL is loaded with load_pac.

API overview

Module Purpose
proxylib.proxy Core types: Proxy, ProxyMap (protocol + factory), SimpleProxyMap, ChainProxyMap, ConfigurableProxyMap, URI parsing
proxylib.patching patch() / unpatch() / register_patcher() — global patching registry
proxylib.env EnvProxyConfig — HTTP_PROXY/HTTPS_PROXY/NO_PROXY
proxylib.os system_proxy() / auto_proxy() — platform dispatch + WPAD fallback
proxylib.os.nt / .darwin Windows (WinHTTP API) / macOS (scutil) system proxy backends
proxylib.os.posix Linux dispatch: .libproxy, .gnome, .mate, .kde, .networkmanager
proxylib.pac PAC, JSProxyAutoConfig, load() — PAC utility functions + evaluation
proxylib.pac.wpad discover() — DNS+HTTP WPAD auto-discovery
proxylib.pac.javascript JSContext — runs a PAC script against a pluggable engine
proxylib.pac.engines JSEngine interface, plus the dukpy/quickjs backends
proxylib.integrations.requests ProxyMapAdapter — the recommended requests integration
proxylib.integrations.urllib ProxyMapHandler — a per-request-aware urllib.request.ProxyHandler
proxylib.integrations.dict ProxyDict — the plain proxies-dict integration
proxylib.netutils get_ip, get_default_port, get_local_interfaces, first_working_proxy

Every ProxyMap implementation (SimpleProxyMap, EnvProxyConfig, PAC, ...) answers the same question: proxymap[url] returns the sequence of Proxy (or None for DIRECT) to try, in order.

Supported Python versions

Python 3.9–3.14. The codebase uses from __future__ import annotations so modern X | Y type syntax can be used everywhere while staying importable on 3.9.

Development

python -m venv .venv/<your-python-version>
.venv/<your-python-version>/Scripts/pip install -e ".[dev,jspac,ifaddr]"
.venv/<your-python-version>/Scripts/pytest -q

Tests that need dukpy/quickjs/ifaddr skip automatically if those extras aren't installed (requests comes from dev, since it's a real test dependency regardless of the requests integration's own optional-import guard).

Releasing

This project follows Semantic Versioning and keeps a CHANGELOG.md. Pushing a tag matching v* (e.g. v1.0.0) triggers .github/workflows/release.yaml, which runs the test suite across platforms/Python versions as a gate, then in parallel: builds the sdist/wheel, creates a GitHub Release (with auto-generated release notes and a diff link against the previous tag) and publishes it to PyPI via Trusted Publishing (no stored token), and builds+publishes the documentation site to GitHub Pages.

Documentation site

API reference docs are built with MkDocs + mkdocstrings from mkdocs.yml/docs/, and published to GitHub Pages on every release (see above). To preview locally:

.venv/<your-python-version>/Scripts/pip install -e ".[docs]"
.venv/<your-python-version>/Scripts/mkdocs serve

Known limitations

  • DHCP-based WPAD discovery is not implemented — only DNS+HTTP (wpad.<domain>/wpad.dat). Reading DHCP option 252 needs raw OS lease access with no portable stdlib path.
  • Linux desktop proxy detection covers libproxy, GNOME/MATE (gsettings), KDE (kioslaverc), and NetworkManager (nmcli, or dbus-send if nmcli isn't installed), tried in that fixed order with no session detection to disambiguate — if a machine has stale config from more than one of these, the first one with anything set wins, even if it isn't the active desktop. Xfce, Cinnamon, and other desktop environments aren't covered directly (though libproxy, if installed, may cover them) — set HTTP_PROXY/HTTPS_PROXY/NO_PROXY or PROXY_PAC explicitly otherwise.
  • The NetworkManager dbus-send fallback path scrapes dbus-send's debug-oriented text output for the specific fields it needs; it hasn't been verified against a live NetworkManager D-Bus session, only a best-effort reconstruction of the expected format. nmcli, when available, is preferred and doesn't have this caveat.
  • dateRange/timeRange implement the documented PAC overload shapes but haven't been exhaustively verified against every real-world PAC file's edge cases.
  • No automatic proxy failover in the adapters themselves — ProxyMapAdapter/ ProxyMapHandler use the first proxy a ProxyMap returns; they don't retry the rest of a PROXY a; PROXY b; DIRECT chain on connection failure. Wrap your map with ConfigurableProxyMap(proxymap, probe=True) (active reachability probing, with a circuit breaker for proxies that keep failing), or call first_working_proxy(proxymap[url]) directly, to pre-select a reachable entry.

License

MIT — see LICENSE.

Metadata

Release files for proxylib 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for proxylib 1.1.0
File Size Uploaded Provenance
proxylib-1.1.0.tar.gz 92.4 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for proxylib 1.1.0
File Interpreter ABI Platform
proxylib-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 162.4 kB

Release files / proxylib-1.1.0.tar.gz

Download URL proxylib-1.1.0.tar.gz
Size 92.4 kB
Tags Source
SHA-256 checksum
How to use checksums
8f62dec81ecf2c9c928596b38e99a108092d92a7dee65b8f91cf5cfef5ffda54
BLAKE2b-256 checksum
How to use checksums
54c94e8be4918764973d6d6c0775e8b828a42c88362ed4f0d13a20a0d7d67e9a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

Release files / proxylib-1.1.0-py3-none-any.whl

Download URL proxylib-1.1.0-py3-none-any.whl
Size 69.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c60f5045d2d675d532232c1c29368a0aa8e77b0689dc581a9cc800f384234a83
BLAKE2b-256 checksum
How to use checksums
852c050af99660383b4cc7d2b0ebdadb66a40d5047f5b77e1f858cc8100ddd6d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

Security for proxylib 1.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for proxylib-1.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page