Загрузить файлы в «venv/Lib/site-packages/pip/_vendor/urllib3/util»
This commit is contained in:
271
venv/Lib/site-packages/pip/_vendor/urllib3/util/timeout.py
Normal file
271
venv/Lib/site-packages/pip/_vendor/urllib3/util/timeout.py
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
# The default socket timeout, used by httplib to indicate that no timeout was; specified by the user
|
||||||
|
from socket import _GLOBAL_DEFAULT_TIMEOUT, getdefaulttimeout
|
||||||
|
|
||||||
|
from ..exceptions import TimeoutStateError
|
||||||
|
|
||||||
|
# A sentinel value to indicate that no timeout was specified by the user in
|
||||||
|
# urllib3
|
||||||
|
_Default = object()
|
||||||
|
|
||||||
|
|
||||||
|
# Use time.monotonic if available.
|
||||||
|
current_time = getattr(time, "monotonic", time.time)
|
||||||
|
|
||||||
|
|
||||||
|
class Timeout(object):
|
||||||
|
"""Timeout configuration.
|
||||||
|
|
||||||
|
Timeouts can be defined as a default for a pool:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
timeout = Timeout(connect=2.0, read=7.0)
|
||||||
|
http = PoolManager(timeout=timeout)
|
||||||
|
response = http.request('GET', 'http://example.com/')
|
||||||
|
|
||||||
|
Or per-request (which overrides the default for the pool):
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
response = http.request('GET', 'http://example.com/', timeout=Timeout(10))
|
||||||
|
|
||||||
|
Timeouts can be disabled by setting all the parameters to ``None``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
no_timeout = Timeout(connect=None, read=None)
|
||||||
|
response = http.request('GET', 'http://example.com/, timeout=no_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
:param total:
|
||||||
|
This combines the connect and read timeouts into one; the read timeout
|
||||||
|
will be set to the time leftover from the connect attempt. In the
|
||||||
|
event that both a connect timeout and a total are specified, or a read
|
||||||
|
timeout and a total are specified, the shorter timeout will be applied.
|
||||||
|
|
||||||
|
Defaults to None.
|
||||||
|
|
||||||
|
:type total: int, float, or None
|
||||||
|
|
||||||
|
:param connect:
|
||||||
|
The maximum amount of time (in seconds) to wait for a connection
|
||||||
|
attempt to a server to succeed. Omitting the parameter will default the
|
||||||
|
connect timeout to the system default, probably `the global default
|
||||||
|
timeout in socket.py
|
||||||
|
<http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_.
|
||||||
|
None will set an infinite timeout for connection attempts.
|
||||||
|
|
||||||
|
:type connect: int, float, or None
|
||||||
|
|
||||||
|
:param read:
|
||||||
|
The maximum amount of time (in seconds) to wait between consecutive
|
||||||
|
read operations for a response from the server. Omitting the parameter
|
||||||
|
will default the read timeout to the system default, probably `the
|
||||||
|
global default timeout in socket.py
|
||||||
|
<http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_.
|
||||||
|
None will set an infinite timeout.
|
||||||
|
|
||||||
|
:type read: int, float, or None
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Many factors can affect the total amount of time for urllib3 to return
|
||||||
|
an HTTP response.
|
||||||
|
|
||||||
|
For example, Python's DNS resolver does not obey the timeout specified
|
||||||
|
on the socket. Other factors that can affect total request time include
|
||||||
|
high CPU load, high swap, the program running at a low priority level,
|
||||||
|
or other behaviors.
|
||||||
|
|
||||||
|
In addition, the read and total timeouts only measure the time between
|
||||||
|
read operations on the socket connecting the client and the server,
|
||||||
|
not the total amount of time for the request to return a complete
|
||||||
|
response. For most requests, the timeout is raised because the server
|
||||||
|
has not sent the first byte in the specified time. This is not always
|
||||||
|
the case; if a server streams one byte every fifteen seconds, a timeout
|
||||||
|
of 20 seconds will not trigger, even though the request will take
|
||||||
|
several minutes to complete.
|
||||||
|
|
||||||
|
If your goal is to cut off any request after a set amount of wall clock
|
||||||
|
time, consider having a second "watcher" thread to cut off a slow
|
||||||
|
request.
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: A sentinel object representing the default timeout value
|
||||||
|
DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT
|
||||||
|
|
||||||
|
def __init__(self, total=None, connect=_Default, read=_Default):
|
||||||
|
self._connect = self._validate_timeout(connect, "connect")
|
||||||
|
self._read = self._validate_timeout(read, "read")
|
||||||
|
self.total = self._validate_timeout(total, "total")
|
||||||
|
self._start_connect = None
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "%s(connect=%r, read=%r, total=%r)" % (
|
||||||
|
type(self).__name__,
|
||||||
|
self._connect,
|
||||||
|
self._read,
|
||||||
|
self.total,
|
||||||
|
)
|
||||||
|
|
||||||
|
# __str__ provided for backwards compatibility
|
||||||
|
__str__ = __repr__
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resolve_default_timeout(cls, timeout):
|
||||||
|
return getdefaulttimeout() if timeout is cls.DEFAULT_TIMEOUT else timeout
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _validate_timeout(cls, value, name):
|
||||||
|
"""Check that a timeout attribute is valid.
|
||||||
|
|
||||||
|
:param value: The timeout value to validate
|
||||||
|
:param name: The name of the timeout attribute to validate. This is
|
||||||
|
used to specify in error messages.
|
||||||
|
:return: The validated and casted version of the given value.
|
||||||
|
:raises ValueError: If it is a numeric value less than or equal to
|
||||||
|
zero, or the type is not an integer, float, or None.
|
||||||
|
"""
|
||||||
|
if value is _Default:
|
||||||
|
return cls.DEFAULT_TIMEOUT
|
||||||
|
|
||||||
|
if value is None or value is cls.DEFAULT_TIMEOUT:
|
||||||
|
return value
|
||||||
|
|
||||||
|
if isinstance(value, bool):
|
||||||
|
raise ValueError(
|
||||||
|
"Timeout cannot be a boolean value. It must "
|
||||||
|
"be an int, float or None."
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
float(value)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
raise ValueError(
|
||||||
|
"Timeout value %s was %s, but it must be an "
|
||||||
|
"int, float or None." % (name, value)
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if value <= 0:
|
||||||
|
raise ValueError(
|
||||||
|
"Attempted to set %s timeout to %s, but the "
|
||||||
|
"timeout cannot be set to a value less "
|
||||||
|
"than or equal to 0." % (name, value)
|
||||||
|
)
|
||||||
|
except TypeError:
|
||||||
|
# Python 3
|
||||||
|
raise ValueError(
|
||||||
|
"Timeout value %s was %s, but it must be an "
|
||||||
|
"int, float or None." % (name, value)
|
||||||
|
)
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_float(cls, timeout):
|
||||||
|
"""Create a new Timeout from a legacy timeout value.
|
||||||
|
|
||||||
|
The timeout value used by httplib.py sets the same timeout on the
|
||||||
|
connect(), and recv() socket requests. This creates a :class:`Timeout`
|
||||||
|
object that sets the individual timeouts to the ``timeout`` value
|
||||||
|
passed to this function.
|
||||||
|
|
||||||
|
:param timeout: The legacy timeout value.
|
||||||
|
:type timeout: integer, float, sentinel default object, or None
|
||||||
|
:return: Timeout object
|
||||||
|
:rtype: :class:`Timeout`
|
||||||
|
"""
|
||||||
|
return Timeout(read=timeout, connect=timeout)
|
||||||
|
|
||||||
|
def clone(self):
|
||||||
|
"""Create a copy of the timeout object
|
||||||
|
|
||||||
|
Timeout properties are stored per-pool but each request needs a fresh
|
||||||
|
Timeout object to ensure each one has its own start/stop configured.
|
||||||
|
|
||||||
|
:return: a copy of the timeout object
|
||||||
|
:rtype: :class:`Timeout`
|
||||||
|
"""
|
||||||
|
# We can't use copy.deepcopy because that will also create a new object
|
||||||
|
# for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to
|
||||||
|
# detect the user default.
|
||||||
|
return Timeout(connect=self._connect, read=self._read, total=self.total)
|
||||||
|
|
||||||
|
def start_connect(self):
|
||||||
|
"""Start the timeout clock, used during a connect() attempt
|
||||||
|
|
||||||
|
:raises urllib3.exceptions.TimeoutStateError: if you attempt
|
||||||
|
to start a timer that has been started already.
|
||||||
|
"""
|
||||||
|
if self._start_connect is not None:
|
||||||
|
raise TimeoutStateError("Timeout timer has already been started.")
|
||||||
|
self._start_connect = current_time()
|
||||||
|
return self._start_connect
|
||||||
|
|
||||||
|
def get_connect_duration(self):
|
||||||
|
"""Gets the time elapsed since the call to :meth:`start_connect`.
|
||||||
|
|
||||||
|
:return: Elapsed time in seconds.
|
||||||
|
:rtype: float
|
||||||
|
:raises urllib3.exceptions.TimeoutStateError: if you attempt
|
||||||
|
to get duration for a timer that hasn't been started.
|
||||||
|
"""
|
||||||
|
if self._start_connect is None:
|
||||||
|
raise TimeoutStateError(
|
||||||
|
"Can't get connect duration for timer that has not started."
|
||||||
|
)
|
||||||
|
return current_time() - self._start_connect
|
||||||
|
|
||||||
|
@property
|
||||||
|
def connect_timeout(self):
|
||||||
|
"""Get the value to use when setting a connection timeout.
|
||||||
|
|
||||||
|
This will be a positive float or integer, the value None
|
||||||
|
(never timeout), or the default system timeout.
|
||||||
|
|
||||||
|
:return: Connect timeout.
|
||||||
|
:rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None
|
||||||
|
"""
|
||||||
|
if self.total is None:
|
||||||
|
return self._connect
|
||||||
|
|
||||||
|
if self._connect is None or self._connect is self.DEFAULT_TIMEOUT:
|
||||||
|
return self.total
|
||||||
|
|
||||||
|
return min(self._connect, self.total)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def read_timeout(self):
|
||||||
|
"""Get the value for the read timeout.
|
||||||
|
|
||||||
|
This assumes some time has elapsed in the connection timeout and
|
||||||
|
computes the read timeout appropriately.
|
||||||
|
|
||||||
|
If self.total is set, the read timeout is dependent on the amount of
|
||||||
|
time taken by the connect timeout. If the connection time has not been
|
||||||
|
established, a :exc:`~urllib3.exceptions.TimeoutStateError` will be
|
||||||
|
raised.
|
||||||
|
|
||||||
|
:return: Value to use for the read timeout.
|
||||||
|
:rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None
|
||||||
|
:raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect`
|
||||||
|
has not yet been called on this object.
|
||||||
|
"""
|
||||||
|
if (
|
||||||
|
self.total is not None
|
||||||
|
and self.total is not self.DEFAULT_TIMEOUT
|
||||||
|
and self._read is not None
|
||||||
|
and self._read is not self.DEFAULT_TIMEOUT
|
||||||
|
):
|
||||||
|
# In case the connect timeout has not yet been established.
|
||||||
|
if self._start_connect is None:
|
||||||
|
return self._read
|
||||||
|
return max(0, min(self.total - self.get_connect_duration(), self._read))
|
||||||
|
elif self.total is not None and self.total is not self.DEFAULT_TIMEOUT:
|
||||||
|
return max(0, self.total - self.get_connect_duration())
|
||||||
|
else:
|
||||||
|
return self._read
|
||||||
435
venv/Lib/site-packages/pip/_vendor/urllib3/util/url.py
Normal file
435
venv/Lib/site-packages/pip/_vendor/urllib3/util/url.py
Normal file
@@ -0,0 +1,435 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import re
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
from ..exceptions import LocationParseError
|
||||||
|
from ..packages import six
|
||||||
|
|
||||||
|
url_attrs = ["scheme", "auth", "host", "port", "path", "query", "fragment"]
|
||||||
|
|
||||||
|
# We only want to normalize urls with an HTTP(S) scheme.
|
||||||
|
# urllib3 infers URLs without a scheme (None) to be http.
|
||||||
|
NORMALIZABLE_SCHEMES = ("http", "https", None)
|
||||||
|
|
||||||
|
# Almost all of these patterns were derived from the
|
||||||
|
# 'rfc3986' module: https://github.com/python-hyper/rfc3986
|
||||||
|
PERCENT_RE = re.compile(r"%[a-fA-F0-9]{2}")
|
||||||
|
SCHEME_RE = re.compile(r"^(?:[a-zA-Z][a-zA-Z0-9+-]*:|/)")
|
||||||
|
URI_RE = re.compile(
|
||||||
|
r"^(?:([a-zA-Z][a-zA-Z0-9+.-]*):)?"
|
||||||
|
r"(?://([^\\/?#]*))?"
|
||||||
|
r"([^?#]*)"
|
||||||
|
r"(?:\?([^#]*))?"
|
||||||
|
r"(?:#(.*))?$",
|
||||||
|
re.UNICODE | re.DOTALL,
|
||||||
|
)
|
||||||
|
|
||||||
|
IPV4_PAT = r"(?:[0-9]{1,3}\.){3}[0-9]{1,3}"
|
||||||
|
HEX_PAT = "[0-9A-Fa-f]{1,4}"
|
||||||
|
LS32_PAT = "(?:{hex}:{hex}|{ipv4})".format(hex=HEX_PAT, ipv4=IPV4_PAT)
|
||||||
|
_subs = {"hex": HEX_PAT, "ls32": LS32_PAT}
|
||||||
|
_variations = [
|
||||||
|
# 6( h16 ":" ) ls32
|
||||||
|
"(?:%(hex)s:){6}%(ls32)s",
|
||||||
|
# "::" 5( h16 ":" ) ls32
|
||||||
|
"::(?:%(hex)s:){5}%(ls32)s",
|
||||||
|
# [ h16 ] "::" 4( h16 ":" ) ls32
|
||||||
|
"(?:%(hex)s)?::(?:%(hex)s:){4}%(ls32)s",
|
||||||
|
# [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
|
||||||
|
"(?:(?:%(hex)s:)?%(hex)s)?::(?:%(hex)s:){3}%(ls32)s",
|
||||||
|
# [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
|
||||||
|
"(?:(?:%(hex)s:){0,2}%(hex)s)?::(?:%(hex)s:){2}%(ls32)s",
|
||||||
|
# [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
|
||||||
|
"(?:(?:%(hex)s:){0,3}%(hex)s)?::%(hex)s:%(ls32)s",
|
||||||
|
# [ *4( h16 ":" ) h16 ] "::" ls32
|
||||||
|
"(?:(?:%(hex)s:){0,4}%(hex)s)?::%(ls32)s",
|
||||||
|
# [ *5( h16 ":" ) h16 ] "::" h16
|
||||||
|
"(?:(?:%(hex)s:){0,5}%(hex)s)?::%(hex)s",
|
||||||
|
# [ *6( h16 ":" ) h16 ] "::"
|
||||||
|
"(?:(?:%(hex)s:){0,6}%(hex)s)?::",
|
||||||
|
]
|
||||||
|
|
||||||
|
UNRESERVED_PAT = r"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._\-~"
|
||||||
|
IPV6_PAT = "(?:" + "|".join([x % _subs for x in _variations]) + ")"
|
||||||
|
ZONE_ID_PAT = "(?:%25|%)(?:[" + UNRESERVED_PAT + "]|%[a-fA-F0-9]{2})+"
|
||||||
|
IPV6_ADDRZ_PAT = r"\[" + IPV6_PAT + r"(?:" + ZONE_ID_PAT + r")?\]"
|
||||||
|
REG_NAME_PAT = r"(?:[^\[\]%:/?#]|%[a-fA-F0-9]{2})*"
|
||||||
|
TARGET_RE = re.compile(r"^(/[^?#]*)(?:\?([^#]*))?(?:#.*)?$")
|
||||||
|
|
||||||
|
IPV4_RE = re.compile("^" + IPV4_PAT + "$")
|
||||||
|
IPV6_RE = re.compile("^" + IPV6_PAT + "$")
|
||||||
|
IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT + "$")
|
||||||
|
BRACELESS_IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT[2:-2] + "$")
|
||||||
|
ZONE_ID_RE = re.compile("(" + ZONE_ID_PAT + r")\]$")
|
||||||
|
|
||||||
|
_HOST_PORT_PAT = ("^(%s|%s|%s)(?::0*?(|0|[1-9][0-9]{0,4}))?$") % (
|
||||||
|
REG_NAME_PAT,
|
||||||
|
IPV4_PAT,
|
||||||
|
IPV6_ADDRZ_PAT,
|
||||||
|
)
|
||||||
|
_HOST_PORT_RE = re.compile(_HOST_PORT_PAT, re.UNICODE | re.DOTALL)
|
||||||
|
|
||||||
|
UNRESERVED_CHARS = set(
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-~"
|
||||||
|
)
|
||||||
|
SUB_DELIM_CHARS = set("!$&'()*+,;=")
|
||||||
|
USERINFO_CHARS = UNRESERVED_CHARS | SUB_DELIM_CHARS | {":"}
|
||||||
|
PATH_CHARS = USERINFO_CHARS | {"@", "/"}
|
||||||
|
QUERY_CHARS = FRAGMENT_CHARS = PATH_CHARS | {"?"}
|
||||||
|
|
||||||
|
|
||||||
|
class Url(namedtuple("Url", url_attrs)):
|
||||||
|
"""
|
||||||
|
Data structure for representing an HTTP URL. Used as a return value for
|
||||||
|
:func:`parse_url`. Both the scheme and host are normalized as they are
|
||||||
|
both case-insensitive according to RFC 3986.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__slots__ = ()
|
||||||
|
|
||||||
|
def __new__(
|
||||||
|
cls,
|
||||||
|
scheme=None,
|
||||||
|
auth=None,
|
||||||
|
host=None,
|
||||||
|
port=None,
|
||||||
|
path=None,
|
||||||
|
query=None,
|
||||||
|
fragment=None,
|
||||||
|
):
|
||||||
|
if path and not path.startswith("/"):
|
||||||
|
path = "/" + path
|
||||||
|
if scheme is not None:
|
||||||
|
scheme = scheme.lower()
|
||||||
|
return super(Url, cls).__new__(
|
||||||
|
cls, scheme, auth, host, port, path, query, fragment
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hostname(self):
|
||||||
|
"""For backwards-compatibility with urlparse. We're nice like that."""
|
||||||
|
return self.host
|
||||||
|
|
||||||
|
@property
|
||||||
|
def request_uri(self):
|
||||||
|
"""Absolute path including the query string."""
|
||||||
|
uri = self.path or "/"
|
||||||
|
|
||||||
|
if self.query is not None:
|
||||||
|
uri += "?" + self.query
|
||||||
|
|
||||||
|
return uri
|
||||||
|
|
||||||
|
@property
|
||||||
|
def netloc(self):
|
||||||
|
"""Network location including host and port"""
|
||||||
|
if self.port:
|
||||||
|
return "%s:%d" % (self.host, self.port)
|
||||||
|
return self.host
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self):
|
||||||
|
"""
|
||||||
|
Convert self into a url
|
||||||
|
|
||||||
|
This function should more or less round-trip with :func:`.parse_url`. The
|
||||||
|
returned url may not be exactly the same as the url inputted to
|
||||||
|
:func:`.parse_url`, but it should be equivalent by the RFC (e.g., urls
|
||||||
|
with a blank port will have : removed).
|
||||||
|
|
||||||
|
Example: ::
|
||||||
|
|
||||||
|
>>> U = parse_url('http://google.com/mail/')
|
||||||
|
>>> U.url
|
||||||
|
'http://google.com/mail/'
|
||||||
|
>>> Url('http', 'username:password', 'host.com', 80,
|
||||||
|
... '/path', 'query', 'fragment').url
|
||||||
|
'http://username:password@host.com:80/path?query#fragment'
|
||||||
|
"""
|
||||||
|
scheme, auth, host, port, path, query, fragment = self
|
||||||
|
url = u""
|
||||||
|
|
||||||
|
# We use "is not None" we want things to happen with empty strings (or 0 port)
|
||||||
|
if scheme is not None:
|
||||||
|
url += scheme + u"://"
|
||||||
|
if auth is not None:
|
||||||
|
url += auth + u"@"
|
||||||
|
if host is not None:
|
||||||
|
url += host
|
||||||
|
if port is not None:
|
||||||
|
url += u":" + str(port)
|
||||||
|
if path is not None:
|
||||||
|
url += path
|
||||||
|
if query is not None:
|
||||||
|
url += u"?" + query
|
||||||
|
if fragment is not None:
|
||||||
|
url += u"#" + fragment
|
||||||
|
|
||||||
|
return url
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.url
|
||||||
|
|
||||||
|
|
||||||
|
def split_first(s, delims):
|
||||||
|
"""
|
||||||
|
.. deprecated:: 1.25
|
||||||
|
|
||||||
|
Given a string and an iterable of delimiters, split on the first found
|
||||||
|
delimiter. Return two split parts and the matched delimiter.
|
||||||
|
|
||||||
|
If not found, then the first part is the full input string.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
>>> split_first('foo/bar?baz', '?/=')
|
||||||
|
('foo', 'bar?baz', '/')
|
||||||
|
>>> split_first('foo/bar?baz', '123')
|
||||||
|
('foo/bar?baz', '', None)
|
||||||
|
|
||||||
|
Scales linearly with number of delims. Not ideal for large number of delims.
|
||||||
|
"""
|
||||||
|
min_idx = None
|
||||||
|
min_delim = None
|
||||||
|
for d in delims:
|
||||||
|
idx = s.find(d)
|
||||||
|
if idx < 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if min_idx is None or idx < min_idx:
|
||||||
|
min_idx = idx
|
||||||
|
min_delim = d
|
||||||
|
|
||||||
|
if min_idx is None or min_idx < 0:
|
||||||
|
return s, "", None
|
||||||
|
|
||||||
|
return s[:min_idx], s[min_idx + 1 :], min_delim
|
||||||
|
|
||||||
|
|
||||||
|
def _encode_invalid_chars(component, allowed_chars, encoding="utf-8"):
|
||||||
|
"""Percent-encodes a URI component without reapplying
|
||||||
|
onto an already percent-encoded component.
|
||||||
|
"""
|
||||||
|
if component is None:
|
||||||
|
return component
|
||||||
|
|
||||||
|
component = six.ensure_text(component)
|
||||||
|
|
||||||
|
# Normalize existing percent-encoded bytes.
|
||||||
|
# Try to see if the component we're encoding is already percent-encoded
|
||||||
|
# so we can skip all '%' characters but still encode all others.
|
||||||
|
component, percent_encodings = PERCENT_RE.subn(
|
||||||
|
lambda match: match.group(0).upper(), component
|
||||||
|
)
|
||||||
|
|
||||||
|
uri_bytes = component.encode("utf-8", "surrogatepass")
|
||||||
|
is_percent_encoded = percent_encodings == uri_bytes.count(b"%")
|
||||||
|
encoded_component = bytearray()
|
||||||
|
|
||||||
|
for i in range(0, len(uri_bytes)):
|
||||||
|
# Will return a single character bytestring on both Python 2 & 3
|
||||||
|
byte = uri_bytes[i : i + 1]
|
||||||
|
byte_ord = ord(byte)
|
||||||
|
if (is_percent_encoded and byte == b"%") or (
|
||||||
|
byte_ord < 128 and byte.decode() in allowed_chars
|
||||||
|
):
|
||||||
|
encoded_component += byte
|
||||||
|
continue
|
||||||
|
encoded_component.extend(b"%" + (hex(byte_ord)[2:].encode().zfill(2).upper()))
|
||||||
|
|
||||||
|
return encoded_component.decode(encoding)
|
||||||
|
|
||||||
|
|
||||||
|
def _remove_path_dot_segments(path):
|
||||||
|
# See http://tools.ietf.org/html/rfc3986#section-5.2.4 for pseudo-code
|
||||||
|
segments = path.split("/") # Turn the path into a list of segments
|
||||||
|
output = [] # Initialize the variable to use to store output
|
||||||
|
|
||||||
|
for segment in segments:
|
||||||
|
# '.' is the current directory, so ignore it, it is superfluous
|
||||||
|
if segment == ".":
|
||||||
|
continue
|
||||||
|
# Anything other than '..', should be appended to the output
|
||||||
|
elif segment != "..":
|
||||||
|
output.append(segment)
|
||||||
|
# In this case segment == '..', if we can, we should pop the last
|
||||||
|
# element
|
||||||
|
elif output:
|
||||||
|
output.pop()
|
||||||
|
|
||||||
|
# If the path starts with '/' and the output is empty or the first string
|
||||||
|
# is non-empty
|
||||||
|
if path.startswith("/") and (not output or output[0]):
|
||||||
|
output.insert(0, "")
|
||||||
|
|
||||||
|
# If the path starts with '/.' or '/..' ensure we add one more empty
|
||||||
|
# string to add a trailing '/'
|
||||||
|
if path.endswith(("/.", "/..")):
|
||||||
|
output.append("")
|
||||||
|
|
||||||
|
return "/".join(output)
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_host(host, scheme):
|
||||||
|
if host:
|
||||||
|
if isinstance(host, six.binary_type):
|
||||||
|
host = six.ensure_str(host)
|
||||||
|
|
||||||
|
if scheme in NORMALIZABLE_SCHEMES:
|
||||||
|
is_ipv6 = IPV6_ADDRZ_RE.match(host)
|
||||||
|
if is_ipv6:
|
||||||
|
# IPv6 hosts of the form 'a::b%zone' are encoded in a URL as
|
||||||
|
# such per RFC 6874: 'a::b%25zone'. Unquote the ZoneID
|
||||||
|
# separator as necessary to return a valid RFC 4007 scoped IP.
|
||||||
|
match = ZONE_ID_RE.search(host)
|
||||||
|
if match:
|
||||||
|
start, end = match.span(1)
|
||||||
|
zone_id = host[start:end]
|
||||||
|
|
||||||
|
if zone_id.startswith("%25") and zone_id != "%25":
|
||||||
|
zone_id = zone_id[3:]
|
||||||
|
else:
|
||||||
|
zone_id = zone_id[1:]
|
||||||
|
zone_id = "%" + _encode_invalid_chars(zone_id, UNRESERVED_CHARS)
|
||||||
|
return host[:start].lower() + zone_id + host[end:]
|
||||||
|
else:
|
||||||
|
return host.lower()
|
||||||
|
elif not IPV4_RE.match(host):
|
||||||
|
return six.ensure_str(
|
||||||
|
b".".join([_idna_encode(label) for label in host.split(".")])
|
||||||
|
)
|
||||||
|
return host
|
||||||
|
|
||||||
|
|
||||||
|
def _idna_encode(name):
|
||||||
|
if name and any(ord(x) >= 128 for x in name):
|
||||||
|
try:
|
||||||
|
from pip._vendor import idna
|
||||||
|
except ImportError:
|
||||||
|
six.raise_from(
|
||||||
|
LocationParseError("Unable to parse URL without the 'idna' module"),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
return idna.encode(name.lower(), strict=True, std3_rules=True)
|
||||||
|
except idna.IDNAError:
|
||||||
|
six.raise_from(
|
||||||
|
LocationParseError(u"Name '%s' is not a valid IDNA label" % name), None
|
||||||
|
)
|
||||||
|
return name.lower().encode("ascii")
|
||||||
|
|
||||||
|
|
||||||
|
def _encode_target(target):
|
||||||
|
"""Percent-encodes a request target so that there are no invalid characters"""
|
||||||
|
path, query = TARGET_RE.match(target).groups()
|
||||||
|
target = _encode_invalid_chars(path, PATH_CHARS)
|
||||||
|
query = _encode_invalid_chars(query, QUERY_CHARS)
|
||||||
|
if query is not None:
|
||||||
|
target += "?" + query
|
||||||
|
return target
|
||||||
|
|
||||||
|
|
||||||
|
def parse_url(url):
|
||||||
|
"""
|
||||||
|
Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is
|
||||||
|
performed to parse incomplete urls. Fields not provided will be None.
|
||||||
|
This parser is RFC 3986 and RFC 6874 compliant.
|
||||||
|
|
||||||
|
The parser logic and helper functions are based heavily on
|
||||||
|
work done in the ``rfc3986`` module.
|
||||||
|
|
||||||
|
:param str url: URL to parse into a :class:`.Url` namedtuple.
|
||||||
|
|
||||||
|
Partly backwards-compatible with :mod:`urlparse`.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
>>> parse_url('http://google.com/mail/')
|
||||||
|
Url(scheme='http', host='google.com', port=None, path='/mail/', ...)
|
||||||
|
>>> parse_url('google.com:80')
|
||||||
|
Url(scheme=None, host='google.com', port=80, path=None, ...)
|
||||||
|
>>> parse_url('/foo?bar')
|
||||||
|
Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...)
|
||||||
|
"""
|
||||||
|
if not url:
|
||||||
|
# Empty
|
||||||
|
return Url()
|
||||||
|
|
||||||
|
source_url = url
|
||||||
|
if not SCHEME_RE.search(url):
|
||||||
|
url = "//" + url
|
||||||
|
|
||||||
|
try:
|
||||||
|
scheme, authority, path, query, fragment = URI_RE.match(url).groups()
|
||||||
|
normalize_uri = scheme is None or scheme.lower() in NORMALIZABLE_SCHEMES
|
||||||
|
|
||||||
|
if scheme:
|
||||||
|
scheme = scheme.lower()
|
||||||
|
|
||||||
|
if authority:
|
||||||
|
auth, _, host_port = authority.rpartition("@")
|
||||||
|
auth = auth or None
|
||||||
|
host, port = _HOST_PORT_RE.match(host_port).groups()
|
||||||
|
if auth and normalize_uri:
|
||||||
|
auth = _encode_invalid_chars(auth, USERINFO_CHARS)
|
||||||
|
if port == "":
|
||||||
|
port = None
|
||||||
|
else:
|
||||||
|
auth, host, port = None, None, None
|
||||||
|
|
||||||
|
if port is not None:
|
||||||
|
port = int(port)
|
||||||
|
if not (0 <= port <= 65535):
|
||||||
|
raise LocationParseError(url)
|
||||||
|
|
||||||
|
host = _normalize_host(host, scheme)
|
||||||
|
|
||||||
|
if normalize_uri and path:
|
||||||
|
path = _remove_path_dot_segments(path)
|
||||||
|
path = _encode_invalid_chars(path, PATH_CHARS)
|
||||||
|
if normalize_uri and query:
|
||||||
|
query = _encode_invalid_chars(query, QUERY_CHARS)
|
||||||
|
if normalize_uri and fragment:
|
||||||
|
fragment = _encode_invalid_chars(fragment, FRAGMENT_CHARS)
|
||||||
|
|
||||||
|
except (ValueError, AttributeError):
|
||||||
|
return six.raise_from(LocationParseError(source_url), None)
|
||||||
|
|
||||||
|
# For the sake of backwards compatibility we put empty
|
||||||
|
# string values for path if there are any defined values
|
||||||
|
# beyond the path in the URL.
|
||||||
|
# TODO: Remove this when we break backwards compatibility.
|
||||||
|
if not path:
|
||||||
|
if query is not None or fragment is not None:
|
||||||
|
path = ""
|
||||||
|
else:
|
||||||
|
path = None
|
||||||
|
|
||||||
|
# Ensure that each part of the URL is a `str` for
|
||||||
|
# backwards compatibility.
|
||||||
|
if isinstance(url, six.text_type):
|
||||||
|
ensure_func = six.ensure_text
|
||||||
|
else:
|
||||||
|
ensure_func = six.ensure_str
|
||||||
|
|
||||||
|
def ensure_type(x):
|
||||||
|
return x if x is None else ensure_func(x)
|
||||||
|
|
||||||
|
return Url(
|
||||||
|
scheme=ensure_type(scheme),
|
||||||
|
auth=ensure_type(auth),
|
||||||
|
host=ensure_type(host),
|
||||||
|
port=port,
|
||||||
|
path=ensure_type(path),
|
||||||
|
query=ensure_type(query),
|
||||||
|
fragment=ensure_type(fragment),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_host(url):
|
||||||
|
"""
|
||||||
|
Deprecated. Use :func:`parse_url` instead.
|
||||||
|
"""
|
||||||
|
p = parse_url(url)
|
||||||
|
return p.scheme or "http", p.hostname, p.port
|
||||||
152
venv/Lib/site-packages/pip/_vendor/urllib3/util/wait.py
Normal file
152
venv/Lib/site-packages/pip/_vendor/urllib3/util/wait.py
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
import errno
|
||||||
|
import select
|
||||||
|
import sys
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
|
try:
|
||||||
|
from time import monotonic
|
||||||
|
except ImportError:
|
||||||
|
from time import time as monotonic
|
||||||
|
|
||||||
|
__all__ = ["NoWayToWaitForSocketError", "wait_for_read", "wait_for_write"]
|
||||||
|
|
||||||
|
|
||||||
|
class NoWayToWaitForSocketError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# How should we wait on sockets?
|
||||||
|
#
|
||||||
|
# There are two types of APIs you can use for waiting on sockets: the fancy
|
||||||
|
# modern stateful APIs like epoll/kqueue, and the older stateless APIs like
|
||||||
|
# select/poll. The stateful APIs are more efficient when you have a lots of
|
||||||
|
# sockets to keep track of, because you can set them up once and then use them
|
||||||
|
# lots of times. But we only ever want to wait on a single socket at a time
|
||||||
|
# and don't want to keep track of state, so the stateless APIs are actually
|
||||||
|
# more efficient. So we want to use select() or poll().
|
||||||
|
#
|
||||||
|
# Now, how do we choose between select() and poll()? On traditional Unixes,
|
||||||
|
# select() has a strange calling convention that makes it slow, or fail
|
||||||
|
# altogether, for high-numbered file descriptors. The point of poll() is to fix
|
||||||
|
# that, so on Unixes, we prefer poll().
|
||||||
|
#
|
||||||
|
# On Windows, there is no poll() (or at least Python doesn't provide a wrapper
|
||||||
|
# for it), but that's OK, because on Windows, select() doesn't have this
|
||||||
|
# strange calling convention; plain select() works fine.
|
||||||
|
#
|
||||||
|
# So: on Windows we use select(), and everywhere else we use poll(). We also
|
||||||
|
# fall back to select() in case poll() is somehow broken or missing.
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 5):
|
||||||
|
# Modern Python, that retries syscalls by default
|
||||||
|
def _retry_on_intr(fn, timeout):
|
||||||
|
return fn(timeout)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Old and broken Pythons.
|
||||||
|
def _retry_on_intr(fn, timeout):
|
||||||
|
if timeout is None:
|
||||||
|
deadline = float("inf")
|
||||||
|
else:
|
||||||
|
deadline = monotonic() + timeout
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
return fn(timeout)
|
||||||
|
# OSError for 3 <= pyver < 3.5, select.error for pyver <= 2.7
|
||||||
|
except (OSError, select.error) as e:
|
||||||
|
# 'e.args[0]' incantation works for both OSError and select.error
|
||||||
|
if e.args[0] != errno.EINTR:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
timeout = deadline - monotonic()
|
||||||
|
if timeout < 0:
|
||||||
|
timeout = 0
|
||||||
|
if timeout == float("inf"):
|
||||||
|
timeout = None
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
def select_wait_for_socket(sock, read=False, write=False, timeout=None):
|
||||||
|
if not read and not write:
|
||||||
|
raise RuntimeError("must specify at least one of read=True, write=True")
|
||||||
|
rcheck = []
|
||||||
|
wcheck = []
|
||||||
|
if read:
|
||||||
|
rcheck.append(sock)
|
||||||
|
if write:
|
||||||
|
wcheck.append(sock)
|
||||||
|
# When doing a non-blocking connect, most systems signal success by
|
||||||
|
# marking the socket writable. Windows, though, signals success by marked
|
||||||
|
# it as "exceptional". We paper over the difference by checking the write
|
||||||
|
# sockets for both conditions. (The stdlib selectors module does the same
|
||||||
|
# thing.)
|
||||||
|
fn = partial(select.select, rcheck, wcheck, wcheck)
|
||||||
|
rready, wready, xready = _retry_on_intr(fn, timeout)
|
||||||
|
return bool(rready or wready or xready)
|
||||||
|
|
||||||
|
|
||||||
|
def poll_wait_for_socket(sock, read=False, write=False, timeout=None):
|
||||||
|
if not read and not write:
|
||||||
|
raise RuntimeError("must specify at least one of read=True, write=True")
|
||||||
|
mask = 0
|
||||||
|
if read:
|
||||||
|
mask |= select.POLLIN
|
||||||
|
if write:
|
||||||
|
mask |= select.POLLOUT
|
||||||
|
poll_obj = select.poll()
|
||||||
|
poll_obj.register(sock, mask)
|
||||||
|
|
||||||
|
# For some reason, poll() takes timeout in milliseconds
|
||||||
|
def do_poll(t):
|
||||||
|
if t is not None:
|
||||||
|
t *= 1000
|
||||||
|
return poll_obj.poll(t)
|
||||||
|
|
||||||
|
return bool(_retry_on_intr(do_poll, timeout))
|
||||||
|
|
||||||
|
|
||||||
|
def null_wait_for_socket(*args, **kwargs):
|
||||||
|
raise NoWayToWaitForSocketError("no select-equivalent available")
|
||||||
|
|
||||||
|
|
||||||
|
def _have_working_poll():
|
||||||
|
# Apparently some systems have a select.poll that fails as soon as you try
|
||||||
|
# to use it, either due to strange configuration or broken monkeypatching
|
||||||
|
# from libraries like eventlet/greenlet.
|
||||||
|
try:
|
||||||
|
poll_obj = select.poll()
|
||||||
|
_retry_on_intr(poll_obj.poll, 0)
|
||||||
|
except (AttributeError, OSError):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_socket(*args, **kwargs):
|
||||||
|
# We delay choosing which implementation to use until the first time we're
|
||||||
|
# called. We could do it at import time, but then we might make the wrong
|
||||||
|
# decision if someone goes wild with monkeypatching select.poll after
|
||||||
|
# we're imported.
|
||||||
|
global wait_for_socket
|
||||||
|
if _have_working_poll():
|
||||||
|
wait_for_socket = poll_wait_for_socket
|
||||||
|
elif hasattr(select, "select"):
|
||||||
|
wait_for_socket = select_wait_for_socket
|
||||||
|
else: # Platform-specific: Appengine.
|
||||||
|
wait_for_socket = null_wait_for_socket
|
||||||
|
return wait_for_socket(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_read(sock, timeout=None):
|
||||||
|
"""Waits for reading to be available on a given socket.
|
||||||
|
Returns True if the socket is readable, or False if the timeout expired.
|
||||||
|
"""
|
||||||
|
return wait_for_socket(sock, read=True, timeout=timeout)
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_write(sock, timeout=None):
|
||||||
|
"""Waits for writing to be available on a given socket.
|
||||||
|
Returns True if the socket is readable, or False if the timeout expired.
|
||||||
|
"""
|
||||||
|
return wait_for_socket(sock, write=True, timeout=timeout)
|
||||||
Reference in New Issue
Block a user