Client integrations
proxylib.integrations.requests
requests integration.
ProxyMapAdapter (requires the requests package -- pip install
requests; there is no proxylib extra for it) is
the recommended way to wire a ProxyMap into a requests.Session — it
hooks HTTPAdapter.send(), so it sees the real request URL. For the
simpler proxies-dict style (requests.get(url, proxies=...)) use
:class:proxylib.integrations.dict.ProxyDict, which isn't requests-specific.
__all__ = ('ProxyMapAdapter',)
module-attribute
__getattr__(name)
Source code in src/proxylib/integrations/requests.py
333 334 335 336 337 338 339 340 341 | |
proxylib.integrations.urllib
urllib.request integration.
ProxyMapHandler resolves the proxy per-request from a ProxyMap,
rather than a static {scheme: proxy_url} dict like the stdlib
urllib.request.ProxyHandler normally uses -- the same upgrade
:class:proxylib.integrations.requests.ProxyMapAdapter is over a plain
proxies dict, and for the same reason: a static dict can't see the request's
host/path, which most ProxyMap rules (PAC scripts, path-dependent
NO_PROXY) need.
__all__ = ('ProxyMapHandler',)
module-attribute
ProxyMapHandler(proxymap)
Bases: ProxyHandler
A urllib.request handler that resolves proxies per-request from a ProxyMap::
opener = urllib.request.build_opener(ProxyMapHandler(proxymap))
opener.open("https://example.com")
# or, to affect every urllib.request.urlopen() call:
urllib.request.install_opener(opener)
When the map has no opinion (KeyError), the request uses the proxy
urllib.request.getproxies() names for its scheme, as the standard
ProxyHandler would -- read by proxylib when it is a PAC result or a
gateway, which urllib cannot use itself.
A URL-prefix gateway gets the request at <gateway><URL> through the
opener's own HTTP(S) handler, and the response keeps the target URL, so
the cookie processor and the redirect handler see the target.
urllib speaks HTTP proxies only, and sends a proxy's headers through a
tunnel unless they are Proxy-Authorization: SOCKS proxies, and (for an
https URL) proxies with other headers, are skipped, and an answer with
nothing else raises :class:~proxylib.UnsupportedProxyError.
Source code in src/proxylib/integrations/urllib.py
53 54 55 56 57 58 | |
ftp_open = _resolve
class-attribute
instance-attribute
http_open = _resolve
class-attribute
instance-attribute
https_open = _resolve
class-attribute
instance-attribute
proxymap = proxymap
instance-attribute
proxylib.integrations.httpx
httpx integration (needs httpx; there is no proxylib extra for it).
ProxyTransport and AsyncProxyTransport resolve the proxy for every
request from a proxy map and fail over along its answer. httpx has no global
hook, so a client opts in::
client = httpx.Client(transport=ProxyTransport(proxymap))
client = httpx.AsyncClient(transport=AsyncProxyTransport(proxymap))
__all__ = ('AsyncProxyTransport', 'ProxyTransport')
module-attribute
__getattr__(name)
Source code in src/proxylib/integrations/httpx.py
182 183 184 185 186 187 188 | |
proxylib.integrations.aiohttp
aiohttp integration (needs aiohttp; there is no proxylib extra for it).
aiohttp has no transport to plug a resolver into, so :class:ProxySession
wraps a ClientSession: every request asks the proxy map and is sent with
proxy= set to the chosen entry, failing over along the answer::
async with ProxySession(proxymap) as session:
async with session.get("https://example.com") as response:
body = await response.text()
__all__ = ('ProxySession',)
module-attribute
ProxySession(proxymap, session=None, *, failover=True, bad_proxy_ttl=300.0, **session_kwargs)
An aiohttp.ClientSession whose requests take their proxy from
proxymap (read with :func:~proxylib.alookup).
session is the session to send through; by default one is made, with
session_kwargs, on the first request and closed by :meth:close. A
session passed in is not closed. request(method, url, **kwargs) and
get/post/put/patch/delete/head/options take
ClientSession.request's arguments.
The answer's entries are tried in order, healthy ones first; with
failover (the default), one that fails to connect
(aiohttp.ClientConnectorError, which includes
ClientProxyConnectionError, or a connect timeout) is marked bad for
bad_proxy_ttl seconds and the next is tried, and the last error is
raised. When the map has no opinion the request goes as aiohttp would
send it. A proxy= argument that is a proxylib value (a PAC result such
as "PROXY a:1; DIRECT", a list of proxies, a Proxy) is resolved
and failed over instead of the map; a plain proxy URL is aiohttp's own.
A proxy's headers go to that proxy only: in the CONNECT of an
https request, as headers of a plain-http one (sent to the proxy). aiohttp speaks HTTP
proxies only: SOCKS proxies and URL-prefix gateways in an answer are
skipped, and an answer with nothing else raises
:class:~proxylib.UnsupportedProxyError. Unless the aiohttp patch
target is installed (the default), a session made with trust_env=True
uses the environment's proxy for a DIRECT entry, so leave that off when
the map decides.
Source code in src/proxylib/integrations/aiohttp.py
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | |
bad_proxy_ttl = bad_proxy_ttl
instance-attribute
failover = failover
instance-attribute
proxymap = proxymap
instance-attribute
session
property
The aiohttp.ClientSession, made on first use.
__aenter__()
async
Source code in src/proxylib/integrations/aiohttp.py
222 223 | |
__aexit__(*exc_info)
async
Source code in src/proxylib/integrations/aiohttp.py
225 226 | |
close()
async
Close the session this wrapper made; a session passed in stays open.
Source code in src/proxylib/integrations/aiohttp.py
217 218 219 220 | |
delete(url, **kwargs)
Source code in src/proxylib/integrations/aiohttp.py
243 244 | |
get(url, **kwargs)
Source code in src/proxylib/integrations/aiohttp.py
231 232 | |
head(url, **kwargs)
Source code in src/proxylib/integrations/aiohttp.py
246 247 | |
options(url, **kwargs)
Source code in src/proxylib/integrations/aiohttp.py
249 250 | |
patch(url, **kwargs)
Source code in src/proxylib/integrations/aiohttp.py
240 241 | |
post(url, **kwargs)
Source code in src/proxylib/integrations/aiohttp.py
234 235 | |
put(url, **kwargs)
Source code in src/proxylib/integrations/aiohttp.py
237 238 | |
request(method, url, **kwargs)
Source code in src/proxylib/integrations/aiohttp.py
228 229 | |
proxylib.integrations.dict
Plain proxies-dict integration: ProxyDict duck-types the
{scheme_or_url: "proxy://uri"} mapping requests and similar
libraries accept, resolving from a ProxyMap.
__all__ = ('ProxyDict',)
module-attribute
ProxyDict(proxymap)
Duck-types the plain {scheme_or_url: "proxy://uri"} proxies dict that
requests and similar libraries accept, resolving from a ProxyMap.
The simpler integration when a Transport Adapter/handler isn't wanted::
requests.get(url, proxies=ProxyDict(proxymap))
Consumers of a proxies dict look keys up by scheme/host, not the full
request URL, so path-dependent rules (most PAC scripts) won't apply --
use ProxyMapAdapter/ProxyMapHandler when that fidelity matters.
Lookups return the first proxy's URI string; DIRECT raises KeyError
(a missing key means "no proxy", matching the dict convention). A URL
string cannot name a URL-prefix gateway or carry proxy headers: such
entries are skipped, and an answer with nothing else raises
:class:~proxylib.UnsupportedProxyError. ProxyMapAdapter resolves a
ProxyDict itself and uses those entries.
Deliberately composes a ProxyMap rather than subclassing it --
__getitem__ here returns a str (a proxy URI), not
Iterable[Optional[Proxy]], which would be an LSP violation if this
were treated as one.
Source code in src/proxylib/integrations/dict.py
43 44 | |
__slots__ = ('proxymap',)
class-attribute
instance-attribute
proxymap = proxymap
instance-attribute
__contains__(key)
Source code in src/proxylib/integrations/dict.py
67 68 69 70 71 72 | |
__getitem__(uri)
Source code in src/proxylib/integrations/dict.py
46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |
copy()
Source code in src/proxylib/integrations/dict.py
74 75 | |
get(uri, default=None)
Source code in src/proxylib/integrations/dict.py
61 62 63 64 65 | |
setdefault(url, value)
No-op: requests calls this to merge env proxies; the ProxyMap wins.
Source code in src/proxylib/integrations/dict.py
77 78 | |