|
""" |
|
Python HTTP library with thread-safe connection pooling, file post support, user friendly, and more |
|
""" |
|
|
|
from __future__ import annotations |
|
|
|
|
|
import logging |
|
import sys |
|
import typing |
|
import warnings |
|
from logging import NullHandler |
|
|
|
from . import exceptions |
|
from ._base_connection import _TYPE_BODY |
|
from ._collections import HTTPHeaderDict |
|
from ._version import __version__ |
|
from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, connection_from_url |
|
from .filepost import _TYPE_FIELDS, encode_multipart_formdata |
|
from .poolmanager import PoolManager, ProxyManager, proxy_from_url |
|
from .response import BaseHTTPResponse, HTTPResponse |
|
from .util.request import make_headers |
|
from .util.retry import Retry |
|
from .util.timeout import Timeout |
|
|
|
|
|
|
|
|
|
try: |
|
import ssl |
|
except ImportError: |
|
pass |
|
else: |
|
if not ssl.OPENSSL_VERSION.startswith("OpenSSL "): |
|
warnings.warn( |
|
"urllib3 v2 only supports OpenSSL 1.1.1+, currently " |
|
f"the 'ssl' module is compiled with {ssl.OPENSSL_VERSION!r}. " |
|
"See: https://github.com/urllib3/urllib3/issues/3020", |
|
exceptions.NotOpenSSLWarning, |
|
) |
|
elif ssl.OPENSSL_VERSION_INFO < (1, 1, 1): |
|
raise ImportError( |
|
"urllib3 v2 only supports OpenSSL 1.1.1+, currently " |
|
f"the 'ssl' module is compiled with {ssl.OPENSSL_VERSION!r}. " |
|
"See: https://github.com/urllib3/urllib3/issues/2168" |
|
) |
|
|
|
__author__ = "Andrey Petrov ([email protected])" |
|
__license__ = "MIT" |
|
__version__ = __version__ |
|
|
|
__all__ = ( |
|
"HTTPConnectionPool", |
|
"HTTPHeaderDict", |
|
"HTTPSConnectionPool", |
|
"PoolManager", |
|
"ProxyManager", |
|
"HTTPResponse", |
|
"Retry", |
|
"Timeout", |
|
"add_stderr_logger", |
|
"connection_from_url", |
|
"disable_warnings", |
|
"encode_multipart_formdata", |
|
"make_headers", |
|
"proxy_from_url", |
|
"request", |
|
"BaseHTTPResponse", |
|
) |
|
|
|
logging.getLogger(__name__).addHandler(NullHandler()) |
|
|
|
|
|
def add_stderr_logger( |
|
level: int = logging.DEBUG, |
|
) -> logging.StreamHandler[typing.TextIO]: |
|
""" |
|
Helper for quickly adding a StreamHandler to the logger. Useful for |
|
debugging. |
|
|
|
Returns the handler after adding it. |
|
""" |
|
|
|
|
|
logger = logging.getLogger(__name__) |
|
handler = logging.StreamHandler() |
|
handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s")) |
|
logger.addHandler(handler) |
|
logger.setLevel(level) |
|
logger.debug("Added a stderr logging handler to logger: %s", __name__) |
|
return handler |
|
|
|
|
|
|
|
del NullHandler |
|
|
|
|
|
|
|
|
|
|
|
|
|
warnings.simplefilter("always", exceptions.SecurityWarning, append=True) |
|
|
|
warnings.simplefilter("default", exceptions.InsecurePlatformWarning, append=True) |
|
|
|
|
|
def disable_warnings(category: type[Warning] = exceptions.HTTPWarning) -> None: |
|
""" |
|
Helper for quickly disabling all urllib3 warnings. |
|
""" |
|
warnings.simplefilter("ignore", category) |
|
|
|
|
|
_DEFAULT_POOL = PoolManager() |
|
|
|
|
|
def request( |
|
method: str, |
|
url: str, |
|
*, |
|
body: _TYPE_BODY | None = None, |
|
fields: _TYPE_FIELDS | None = None, |
|
headers: typing.Mapping[str, str] | None = None, |
|
preload_content: bool | None = True, |
|
decode_content: bool | None = True, |
|
redirect: bool | None = True, |
|
retries: Retry | bool | int | None = None, |
|
timeout: Timeout | float | int | None = 3, |
|
json: typing.Any | None = None, |
|
) -> BaseHTTPResponse: |
|
""" |
|
A convenience, top-level request method. It uses a module-global ``PoolManager`` instance. |
|
Therefore, its side effects could be shared across dependencies relying on it. |
|
To avoid side effects create a new ``PoolManager`` instance and use it instead. |
|
The method does not accept low-level ``**urlopen_kw`` keyword arguments. |
|
|
|
:param method: |
|
HTTP request method (such as GET, POST, PUT, etc.) |
|
|
|
:param url: |
|
The URL to perform the request on. |
|
|
|
:param body: |
|
Data to send in the request body, either :class:`str`, :class:`bytes`, |
|
an iterable of :class:`str`/:class:`bytes`, or a file-like object. |
|
|
|
:param fields: |
|
Data to encode and send in the request body. |
|
|
|
:param headers: |
|
Dictionary of custom headers to send, such as User-Agent, |
|
If-None-Match, etc. |
|
|
|
:param bool preload_content: |
|
If True, the response's body will be preloaded into memory. |
|
|
|
:param bool decode_content: |
|
If True, will attempt to decode the body based on the |
|
'content-encoding' header. |
|
|
|
:param redirect: |
|
If True, automatically handle redirects (status codes 301, 302, |
|
303, 307, 308). Each redirect counts as a retry. Disabling retries |
|
will disable redirect, too. |
|
|
|
:param retries: |
|
Configure the number of retries to allow before raising a |
|
:class:`~urllib3.exceptions.MaxRetryError` exception. |
|
|
|
If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a |
|
:class:`~urllib3.util.retry.Retry` object for fine-grained control |
|
over different types of retries. |
|
Pass an integer number to retry connection errors that many times, |
|
but no other types of errors. Pass zero to never retry. |
|
|
|
If ``False``, then retries are disabled and any exception is raised |
|
immediately. Also, instead of raising a MaxRetryError on redirects, |
|
the redirect response will be returned. |
|
|
|
:type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. |
|
|
|
:param timeout: |
|
If specified, overrides the default timeout for this one |
|
request. It may be a float (in seconds) or an instance of |
|
:class:`urllib3.util.Timeout`. |
|
|
|
:param json: |
|
Data to encode and send as JSON with UTF-encoded in the request body. |
|
The ``"Content-Type"`` header will be set to ``"application/json"`` |
|
unless specified otherwise. |
|
""" |
|
|
|
return _DEFAULT_POOL.request( |
|
method, |
|
url, |
|
body=body, |
|
fields=fields, |
|
headers=headers, |
|
preload_content=preload_content, |
|
decode_content=decode_content, |
|
redirect=redirect, |
|
retries=retries, |
|
timeout=timeout, |
|
json=json, |
|
) |
|
|
|
|
|
if sys.platform == "emscripten": |
|
from .contrib.emscripten import inject_into_urllib3 |
|
|
|
inject_into_urllib3() |
|
|