aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2023-11-18 09:45:45 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2023-11-18 10:04:04 +0300
commitdf03ef42eed0a5b601011204e47b72d37c6373a9 (patch)
tree530e7eed0215db0b677aa07c5ccc834a8cb60e5a
parent02af688a175993fc8169edf79bef767977b91764 (diff)
downloadydb-df03ef42eed0a5b601011204e47b72d37c6373a9.tar.gz
Intermediate changes
-rw-r--r--contrib/python/httpx/.dist-info/METADATA23
-rw-r--r--contrib/python/httpx/httpx/__version__.py2
-rw-r--r--contrib/python/httpx/httpx/_auth.py9
-rw-r--r--contrib/python/httpx/httpx/_compat.py4
-rw-r--r--contrib/python/httpx/httpx/_config.py17
-rw-r--r--contrib/python/httpx/httpx/_models.py17
-rw-r--r--contrib/python/httpx/httpx/_multipart.py3
-rw-r--r--contrib/python/httpx/httpx/_transports/default.py2
-rw-r--r--contrib/python/httpx/httpx/_urlparse.py2
-rw-r--r--contrib/python/httpx/httpx/_utils.py35
-rw-r--r--contrib/python/httpx/ya.make3
-rw-r--r--contrib/python/responses/py3/.dist-info/METADATA71
-rw-r--r--contrib/python/responses/py3/README.rst55
-rw-r--r--contrib/python/responses/py3/responses/__init__.py199
-rw-r--r--contrib/python/responses/py3/responses/matchers.py34
-rw-r--r--contrib/python/responses/py3/responses/registries.py6
-rw-r--r--contrib/python/responses/py3/ya.make3
-rw-r--r--contrib/python/types-PyYAML/.dist-info/METADATA31
-rw-r--r--contrib/python/types-PyYAML/.dist-info/top_level.txt1
-rw-r--r--contrib/python/types-PyYAML/ya.make40
-rw-r--r--contrib/python/types-PyYAML/yaml-stubs/METADATA.toml2
21 files changed, 286 insertions, 273 deletions
diff --git a/contrib/python/httpx/.dist-info/METADATA b/contrib/python/httpx/.dist-info/METADATA
index f3a6d509cd..e4abd6660e 100644
--- a/contrib/python/httpx/.dist-info/METADATA
+++ b/contrib/python/httpx/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: httpx
-Version: 0.25.0
+Version: 0.25.1
Summary: The next generation HTTP client.
Project-URL: Changelog, https://github.com/encode/httpx/blob/master/CHANGELOG.md
Project-URL: Documentation, https://www.python-httpx.org
@@ -22,10 +22,12 @@ Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP
Requires-Python: >=3.8
+Requires-Dist: anyio
Requires-Dist: certifi
-Requires-Dist: httpcore<0.19.0,>=0.18.0
+Requires-Dist: httpcore
Requires-Dist: idna
Requires-Dist: sniffio
Provides-Extra: brotli
@@ -192,23 +194,14 @@ inspiration around the lower-level networking details.
## Release Information
-### Removed
+### 0.25.1 (3rd November, 2023)
-* Drop support for Python 3.7. (#2813)
-
-### Added
-
-* Support HTTPS proxies. (#2845)
-* Change the type of `Extensions` from `Mapping[Str, Any]` to `MutableMapping[Str, Any]`. (#2803)
-* Add `socket_options` argument to `httpx.HTTPTransport` and `httpx.AsyncHTTPTransport` classes. (#2716)
-* The `Response.raise_for_status()` method now returns the response instance. For example: `data = httpx.get('...').raise_for_status().json()`. (#2776)
+* Add support for Python 3.12. (#2854)
+* Add support for httpcore 1.0 (#2885)
### Fixed
-* Return `500` error response instead of exceptions when `raise_app_exceptions=False` is set on `ASGITransport`. (#2669)
-* Ensure all `WSGITransport` environs have a `SERVER_PROTOCOL`. (#2708)
-* Always encode forward slashes as `%2F` in query parameters (#2723)
-* Use Mozilla documentation instead of `httpstatuses.com` for HTTP error reference (#2768)
+* Raise `ValueError` on `Response.encoding` being set after `Response.text` has been accessed. (#2852)
---
diff --git a/contrib/python/httpx/httpx/__version__.py b/contrib/python/httpx/httpx/__version__.py
index bfa421ad60..9f92ef99b9 100644
--- a/contrib/python/httpx/httpx/__version__.py
+++ b/contrib/python/httpx/httpx/__version__.py
@@ -1,3 +1,3 @@
__title__ = "httpx"
__description__ = "A next generation HTTP client, for Python 3."
-__version__ = "0.25.0"
+__version__ = "0.25.1"
diff --git a/contrib/python/httpx/httpx/_auth.py b/contrib/python/httpx/httpx/_auth.py
index 1d7385d573..c2c38f3945 100644
--- a/contrib/python/httpx/httpx/_auth.py
+++ b/contrib/python/httpx/httpx/_auth.py
@@ -1,5 +1,4 @@
import hashlib
-import netrc
import os
import re
import time
@@ -8,7 +7,7 @@ from base64 import b64encode
from urllib.request import parse_http_list
from ._exceptions import ProtocolError
-from ._models import Request, Response
+from ._models import Cookies, Request, Response
from ._utils import to_bytes, to_str, unquote
if typing.TYPE_CHECKING: # pragma: no cover
@@ -148,6 +147,10 @@ class NetRCAuth(Auth):
"""
def __init__(self, file: typing.Optional[str] = None):
+ # Lazily import 'netrc'.
+ # There's no need for us to load this module unless 'NetRCAuth' is being used.
+ import netrc
+
self._netrc_info = netrc.netrc(file)
def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]:
@@ -217,6 +220,8 @@ class DigestAuth(Auth):
request.headers["Authorization"] = self._build_auth_header(
request, self._last_challenge
)
+ if response.cookies:
+ Cookies(response.cookies).set_cookie_header(request=request)
yield request
def _parse_challenge(
diff --git a/contrib/python/httpx/httpx/_compat.py b/contrib/python/httpx/httpx/_compat.py
index a271c6b800..493e621087 100644
--- a/contrib/python/httpx/httpx/_compat.py
+++ b/contrib/python/httpx/httpx/_compat.py
@@ -16,9 +16,7 @@ except ImportError: # pragma: no cover
except ImportError:
brotli = None
-if sys.version_info >= (3, 10) or (
- sys.version_info >= (3, 8) and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0, 7)
-):
+if sys.version_info >= (3, 10) or ssl.OPENSSL_VERSION_INFO >= (1, 1, 0, 7):
def set_minimum_tls_version_1_2(context: ssl.SSLContext) -> None:
# The OP_NO_SSL* and OP_NO_TLS* become deprecated in favor of
diff --git a/contrib/python/httpx/httpx/_config.py b/contrib/python/httpx/httpx/_config.py
index 8d4e03add5..50bcede7f7 100644
--- a/contrib/python/httpx/httpx/_config.py
+++ b/contrib/python/httpx/httpx/_config.py
@@ -1,7 +1,6 @@
import logging
import os
import ssl
-import sys
import typing
from pathlib import Path
@@ -132,11 +131,10 @@ class SSLConfig:
# Signal to server support for PHA in TLS 1.3. Raises an
# AttributeError if only read-only access is implemented.
- if sys.version_info >= (3, 8): # pragma: no cover
- try:
- context.post_handshake_auth = True
- except AttributeError: # pragma: no cover
- pass
+ try:
+ context.post_handshake_auth = True
+ except AttributeError: # pragma: no cover
+ pass
# Disable using 'commonName' for SSLContext.check_hostname
# when the 'subjectAltName' extension isn't available.
@@ -175,10 +173,9 @@ class SSLConfig:
alpn_idents = ["http/1.1", "h2"] if self.http2 else ["http/1.1"]
context.set_alpn_protocols(alpn_idents)
- if sys.version_info >= (3, 8): # pragma: no cover
- keylogfile = os.environ.get("SSLKEYLOGFILE")
- if keylogfile and self.trust_env:
- context.keylog_filename = keylogfile
+ keylogfile = os.environ.get("SSLKEYLOGFILE")
+ if keylogfile and self.trust_env:
+ context.keylog_filename = keylogfile
return context
diff --git a/contrib/python/httpx/httpx/_models.py b/contrib/python/httpx/httpx/_models.py
index e1e45cf06b..4e4162db1a 100644
--- a/contrib/python/httpx/httpx/_models.py
+++ b/contrib/python/httpx/httpx/_models.py
@@ -43,7 +43,6 @@ from ._types import (
)
from ._urls import URL
from ._utils import (
- guess_json_utf,
is_known_encoding,
normalize_header_key,
normalize_header_value,
@@ -603,6 +602,16 @@ class Response:
@encoding.setter
def encoding(self, value: str) -> None:
+ """
+ Set the encoding to use for decoding the byte content into text.
+
+ If the `text` attribute has been accessed, attempting to set the
+ encoding will throw a ValueError.
+ """
+ if hasattr(self, "_text"):
+ raise ValueError(
+ "Setting encoding after `text` has been accessed is not allowed."
+ )
self._encoding = value
@property
@@ -749,11 +758,7 @@ class Response:
raise HTTPStatusError(message, request=request, response=self)
def json(self, **kwargs: typing.Any) -> typing.Any:
- if self.charset_encoding is None and self.content and len(self.content) > 3:
- encoding = guess_json_utf(self.content)
- if encoding is not None:
- return jsonlib.loads(self.content.decode(encoding), **kwargs)
- return jsonlib.loads(self.text, **kwargs)
+ return jsonlib.loads(self.content, **kwargs)
@property
def cookies(self) -> "Cookies":
diff --git a/contrib/python/httpx/httpx/_multipart.py b/contrib/python/httpx/httpx/_multipart.py
index 446f4ad2df..6d5baa8639 100644
--- a/contrib/python/httpx/httpx/_multipart.py
+++ b/contrib/python/httpx/httpx/_multipart.py
@@ -1,4 +1,3 @@
-import binascii
import io
import os
import typing
@@ -200,7 +199,7 @@ class MultipartStream(SyncByteStream, AsyncByteStream):
boundary: typing.Optional[bytes] = None,
) -> None:
if boundary is None:
- boundary = binascii.hexlify(os.urandom(16))
+ boundary = os.urandom(16).hex().encode("ascii")
self.boundary = boundary
self.content_type = "multipart/form-data; boundary=%s" % boundary.decode(
diff --git a/contrib/python/httpx/httpx/_transports/default.py b/contrib/python/httpx/httpx/_transports/default.py
index 7dba5b8208..76c543ce4e 100644
--- a/contrib/python/httpx/httpx/_transports/default.py
+++ b/contrib/python/httpx/httpx/_transports/default.py
@@ -64,7 +64,7 @@ SOCKET_OPTION = typing.Union[
def map_httpcore_exceptions() -> typing.Iterator[None]:
try:
yield
- except Exception as exc: # noqa: PIE-786
+ except Exception as exc:
mapped_exc = None
for from_exc, to_exc in HTTPCORE_EXC_MAP.items():
diff --git a/contrib/python/httpx/httpx/_urlparse.py b/contrib/python/httpx/httpx/_urlparse.py
index e1ba8dcdb7..8e060424e8 100644
--- a/contrib/python/httpx/httpx/_urlparse.py
+++ b/contrib/python/httpx/httpx/_urlparse.py
@@ -87,7 +87,7 @@ COMPONENT_REGEX = {
# We use these simple regexs as a first pass before handing off to
# the stdlib 'ipaddress' module for IP address validation.
-IPv4_STYLE_HOSTNAME = re.compile(r"^[0-9]+.[0-9]+.[0-9]+.[0-9]+$")
+IPv4_STYLE_HOSTNAME = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$")
IPv6_STYLE_HOSTNAME = re.compile(r"^\[.*\]$")
diff --git a/contrib/python/httpx/httpx/_utils.py b/contrib/python/httpx/httpx/_utils.py
index 1775b1a1ef..ba5807c048 100644
--- a/contrib/python/httpx/httpx/_utils.py
+++ b/contrib/python/httpx/httpx/_utils.py
@@ -91,41 +91,6 @@ def format_form_param(name: str, value: str) -> bytes:
return f'{name}="{value}"'.encode()
-# Null bytes; no need to recreate these on each call to guess_json_utf
-_null = b"\x00"
-_null2 = _null * 2
-_null3 = _null * 3
-
-
-def guess_json_utf(data: bytes) -> typing.Optional[str]:
- # JSON always starts with two ASCII characters, so detection is as
- # easy as counting the nulls and from their location and count
- # determine the encoding. Also detect a BOM, if present.
- sample = data[:4]
- if sample in (codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE):
- return "utf-32" # BOM included
- if sample[:3] == codecs.BOM_UTF8:
- return "utf-8-sig" # BOM included, MS style (discouraged)
- if sample[:2] in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE):
- return "utf-16" # BOM included
- nullcount = sample.count(_null)
- if nullcount == 0:
- return "utf-8"
- if nullcount == 2:
- if sample[::2] == _null2: # 1st and 3rd are null
- return "utf-16-be"
- if sample[1::2] == _null2: # 2nd and 4th are null
- return "utf-16-le"
- # Did not detect 2 valid UTF-16 ascii-range characters
- if nullcount == 3:
- if sample[:3] == _null3:
- return "utf-32-be"
- if sample[1:] == _null3:
- return "utf-32-le"
- # Did not detect a valid UTF-32 ascii-range character
- return None
-
-
def get_ca_bundle_from_env() -> typing.Optional[str]:
if "SSL_CERT_FILE" in os.environ:
ssl_file = Path(os.environ["SSL_CERT_FILE"])
diff --git a/contrib/python/httpx/ya.make b/contrib/python/httpx/ya.make
index 850e354ef0..112b04e998 100644
--- a/contrib/python/httpx/ya.make
+++ b/contrib/python/httpx/ya.make
@@ -2,11 +2,12 @@
PY3_LIBRARY()
-VERSION(0.25.0)
+VERSION(0.25.1)
LICENSE(BSD-3-Clause)
PEERDIR(
+ contrib/python/anyio
contrib/python/certifi
contrib/python/httpcore
contrib/python/idna
diff --git a/contrib/python/responses/py3/.dist-info/METADATA b/contrib/python/responses/py3/.dist-info/METADATA
index 9d56ee6bec..1604e06711 100644
--- a/contrib/python/responses/py3/.dist-info/METADATA
+++ b/contrib/python/responses/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: responses
-Version: 0.23.3
+Version: 0.24.0
Summary: A utility library for mocking out the `requests` Python library.
Home-page: https://github.com/getsentry/responses
Author: David Cramer
@@ -15,27 +15,25 @@ Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Software Development
-Requires-Python: >=3.7
+Requires-Python: >=3.8
Description-Content-Type: text/x-rst
License-File: LICENSE
-Requires-Dist: requests (<3.0,>=2.30.0)
-Requires-Dist: urllib3 (<3.0,>=1.25.10)
+Requires-Dist: requests <3.0,>=2.30.0
+Requires-Dist: urllib3 <3.0,>=1.25.10
Requires-Dist: pyyaml
-Requires-Dist: types-PyYAML
-Requires-Dist: typing-extensions ; python_version < "3.8"
Provides-Extra: tests
-Requires-Dist: pytest (>=7.0.0) ; extra == 'tests'
-Requires-Dist: coverage (>=6.0.0) ; extra == 'tests'
+Requires-Dist: pytest >=7.0.0 ; extra == 'tests'
+Requires-Dist: coverage >=6.0.0 ; extra == 'tests'
Requires-Dist: pytest-cov ; extra == 'tests'
Requires-Dist: pytest-asyncio ; extra == 'tests'
Requires-Dist: pytest-httpserver ; extra == 'tests'
Requires-Dist: flake8 ; extra == 'tests'
+Requires-Dist: types-PyYAML ; extra == 'tests'
Requires-Dist: types-requests ; extra == 'tests'
Requires-Dist: mypy ; extra == 'tests'
Requires-Dist: tomli-w ; extra == 'tests'
@@ -60,7 +58,7 @@ A utility library for mocking out the ``requests`` Python library.
.. note::
- Responses requires Python 3.7 or newer, and requests >= 2.30.0
+ Responses requires Python 3.8 or newer, and requests >= 2.30.0
Table of Contents
@@ -1122,6 +1120,59 @@ Assert that the request was called exactly n times.
responses.assert_call_count("http://www.example.com?hello=world", 1) is True
+Assert Request Calls data
+-------------------------
+
+``Request`` object has ``calls`` list which elements correspond to ``Call`` objects
+in the global list of ``Registry``. This can be useful when the order of requests is not
+guaranteed, but you need to check their correctness, for example in multithreaded
+applications.
+
+.. code-block:: python
+
+ import concurrent.futures
+ import responses
+ import requests
+
+
+ @responses.activate
+ def test_assert_calls_on_resp():
+ rsp1 = responses.patch("http://www.foo.bar/1/", status=200)
+ rsp2 = responses.patch("http://www.foo.bar/2/", status=400)
+ rsp3 = responses.patch("http://www.foo.bar/3/", status=200)
+
+ def update_user(uid, is_active):
+ url = f"http://www.foo.bar/{uid}/"
+ response = requests.patch(url, json={"is_active": is_active})
+ return response
+
+ with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
+ future_to_uid = {
+ executor.submit(update_user, uid, is_active): uid
+ for (uid, is_active) in [("3", True), ("2", True), ("1", False)]
+ }
+ for future in concurrent.futures.as_completed(future_to_uid):
+ uid = future_to_uid[future]
+ response = future.result()
+ print(f"{uid} updated with {response.status_code} status code")
+
+ assert len(responses.calls) == 3 # total calls count
+
+ assert rsp1.call_count == 1
+ assert rsp1.calls[0] in responses.calls
+ assert rsp1.calls[0].response.status_code == 200
+ assert json.loads(rsp1.calls[0].request.body) == {"is_active": False}
+
+ assert rsp2.call_count == 1
+ assert rsp2.calls[0] in responses.calls
+ assert rsp2.calls[0].response.status_code == 400
+ assert json.loads(rsp2.calls[0].request.body) == {"is_active": True}
+
+ assert rsp3.call_count == 1
+ assert rsp3.calls[0] in responses.calls
+ assert rsp3.calls[0].response.status_code == 200
+ assert json.loads(rsp3.calls[0].request.body) == {"is_active": True}
+
Multiple Responses
------------------
diff --git a/contrib/python/responses/py3/README.rst b/contrib/python/responses/py3/README.rst
index 7d790eb0e3..e2096c6cae 100644
--- a/contrib/python/responses/py3/README.rst
+++ b/contrib/python/responses/py3/README.rst
@@ -17,7 +17,7 @@ A utility library for mocking out the ``requests`` Python library.
.. note::
- Responses requires Python 3.7 or newer, and requests >= 2.30.0
+ Responses requires Python 3.8 or newer, and requests >= 2.30.0
Table of Contents
@@ -1079,6 +1079,59 @@ Assert that the request was called exactly n times.
responses.assert_call_count("http://www.example.com?hello=world", 1) is True
+Assert Request Calls data
+-------------------------
+
+``Request`` object has ``calls`` list which elements correspond to ``Call`` objects
+in the global list of ``Registry``. This can be useful when the order of requests is not
+guaranteed, but you need to check their correctness, for example in multithreaded
+applications.
+
+.. code-block:: python
+
+ import concurrent.futures
+ import responses
+ import requests
+
+
+ @responses.activate
+ def test_assert_calls_on_resp():
+ rsp1 = responses.patch("http://www.foo.bar/1/", status=200)
+ rsp2 = responses.patch("http://www.foo.bar/2/", status=400)
+ rsp3 = responses.patch("http://www.foo.bar/3/", status=200)
+
+ def update_user(uid, is_active):
+ url = f"http://www.foo.bar/{uid}/"
+ response = requests.patch(url, json={"is_active": is_active})
+ return response
+
+ with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
+ future_to_uid = {
+ executor.submit(update_user, uid, is_active): uid
+ for (uid, is_active) in [("3", True), ("2", True), ("1", False)]
+ }
+ for future in concurrent.futures.as_completed(future_to_uid):
+ uid = future_to_uid[future]
+ response = future.result()
+ print(f"{uid} updated with {response.status_code} status code")
+
+ assert len(responses.calls) == 3 # total calls count
+
+ assert rsp1.call_count == 1
+ assert rsp1.calls[0] in responses.calls
+ assert rsp1.calls[0].response.status_code == 200
+ assert json.loads(rsp1.calls[0].request.body) == {"is_active": False}
+
+ assert rsp2.call_count == 1
+ assert rsp2.calls[0] in responses.calls
+ assert rsp2.calls[0].response.status_code == 400
+ assert json.loads(rsp2.calls[0].request.body) == {"is_active": True}
+
+ assert rsp3.call_count == 1
+ assert rsp3.calls[0] in responses.calls
+ assert rsp3.calls[0].response.status_code == 200
+ assert json.loads(rsp3.calls[0].request.body) == {"is_active": True}
+
Multiple Responses
------------------
diff --git a/contrib/python/responses/py3/responses/__init__.py b/contrib/python/responses/py3/responses/__init__.py
index 2666b7c8bc..0e74f9b907 100644
--- a/contrib/python/responses/py3/responses/__init__.py
+++ b/contrib/python/responses/py3/responses/__init__.py
@@ -1,6 +1,8 @@
+import http
import inspect
import json as json_module
import logging
+import socket
from collections import namedtuple
from functools import partialmethod
from functools import wraps
@@ -22,7 +24,6 @@ from typing import Sized
from typing import Tuple
from typing import Type
from typing import Union
-from typing import overload
from warnings import warn
import yaml
@@ -41,20 +42,6 @@ try:
except ImportError: # pragma: no cover
from typing import Literal # type: ignore # pragma: no cover
-try:
- from requests.packages.urllib3.response import HTTPResponse
-except ImportError: # pragma: no cover
- from urllib3.response import HTTPResponse # pragma: no cover
-
-try:
- from requests.packages.urllib3.connection import HTTPHeaderDict
-except ImportError: # pragma: no cover
- from urllib3.response import HTTPHeaderDict # type: ignore[attr-defined]
-try:
- from requests.packages.urllib3.util.url import parse_url
-except ImportError: # pragma: no cover
- from urllib3.util.url import parse_url # pragma: no cover
-
from io import BufferedReader
from io import BytesIO
from unittest import mock as std_mock
@@ -64,6 +51,10 @@ from urllib.parse import urlsplit
from urllib.parse import urlunparse
from urllib.parse import urlunsplit
+from urllib3.response import HTTPHeaderDict
+from urllib3.response import HTTPResponse
+from urllib3.util.url import parse_url
+
if TYPE_CHECKING: # pragma: no cover
# import only for linter run
import os
@@ -84,14 +75,25 @@ if TYPE_CHECKING: # pragma: no cover
) -> models.Response:
...
-
-# Block of type annotations
-_Body = Union[str, BaseException, "Response", BufferedReader, bytes, None]
-_F = Callable[..., Any]
-_HeaderSet = Optional[Union[Mapping[str, str], List[Tuple[str, str]]]]
-_MatcherIterable = Iterable[Callable[..., Tuple[bool, str]]]
-_HTTPMethodOrResponse = Optional[Union[str, "BaseResponse"]]
-_URLPatternType = Union["Pattern[str]", str]
+ # Block of type annotations
+ _Body = Union[str, BaseException, "Response", BufferedReader, bytes, None]
+ _F = Callable[..., Any]
+ _HeaderSet = Optional[Union[Mapping[str, str], List[Tuple[str, str]]]]
+ _MatcherIterable = Iterable[Callable[..., Tuple[bool, str]]]
+ _HTTPMethodOrResponse = Optional[Union[str, "BaseResponse"]]
+ _URLPatternType = Union["Pattern[str]", str]
+ _HTTPAdapterSend = Callable[
+ [
+ HTTPAdapter,
+ PreparedRequest,
+ bool,
+ Union[float, Tuple[float, float], Tuple[float, None], None],
+ Union[bool, str],
+ Union[bytes, str, Tuple[Union[bytes, str], Union[bytes, str]], None],
+ Optional[Mapping[str, str]],
+ ],
+ models.Response,
+ ]
Call = namedtuple("Call", ["request", "response"])
@@ -111,8 +113,6 @@ class FalseBool:
def __bool__(self) -> bool:
return False
- __nonzero__ = __bool__
-
def urlencoded_params_matcher(params: Optional[Dict[str, str]]) -> Callable[..., Any]:
warn(
@@ -241,27 +241,22 @@ class CallList(Sequence[Any], Sized):
def __len__(self) -> int:
return len(self._calls)
- @overload
- def __getitem__(self, idx: int) -> Call:
- """Overload when get a single item."""
-
- @overload
- def __getitem__(self, idx: slice) -> List[Call]:
- """Overload when a slice is requested."""
-
def __getitem__(self, idx: Union[int, slice]) -> Union[Call, List[Call]]:
return self._calls[idx]
- def add(self, request: "PreparedRequest", response: _Body) -> None:
+ def add(self, request: "PreparedRequest", response: "_Body") -> None:
self._calls.append(Call(request, response))
+ def add_call(self, call: Call) -> None:
+ self._calls.append(call)
+
def reset(self) -> None:
self._calls = []
def _ensure_url_default_path(
- url: _URLPatternType,
-) -> _URLPatternType:
+ url: "_URLPatternType",
+) -> "_URLPatternType":
"""Add empty URL path '/' if doesn't exist.
Examples
@@ -369,7 +364,7 @@ def _handle_body(
return data
-class BaseResponse(object):
+class BaseResponse:
passthrough: bool = False
content_type: Optional[str] = None
headers: Optional[Mapping[str, str]] = None
@@ -378,7 +373,7 @@ class BaseResponse(object):
def __init__(
self,
method: str,
- url: _URLPatternType,
+ url: "_URLPatternType",
match_querystring: Union[bool, object] = None,
match: "_MatcherIterable" = (),
*,
@@ -386,7 +381,7 @@ class BaseResponse(object):
) -> None:
self.method: str = method
# ensure the url has a default path set if the url is a string
- self.url: _URLPatternType = _ensure_url_default_path(url)
+ self.url: "_URLPatternType" = _ensure_url_default_path(url)
if self._should_match_querystring(match_querystring):
match = tuple(match) + (
@@ -394,7 +389,7 @@ class BaseResponse(object):
)
self.match: "_MatcherIterable" = match
- self.call_count: int = 0
+ self._calls: CallList = CallList()
self.passthrough = passthrough
def __eq__(self, other: Any) -> bool:
@@ -436,7 +431,7 @@ class BaseResponse(object):
return bool(urlsplit(self.url).query)
- def _url_matches(self, url: _URLPatternType, other: str) -> bool:
+ def _url_matches(self, url: "_URLPatternType", other: str) -> bool:
"""Compares two URLs.
Compares only scheme, netloc and path. If 'url' is a re.Pattern, then checks that
@@ -481,10 +476,17 @@ class BaseResponse(object):
def get_headers(self) -> HTTPHeaderDict:
headers = HTTPHeaderDict() # Duplicate headers are legal
- if self.content_type is not None:
+
+ # Add Content-Type if it exists and is not already in headers
+ if self.content_type and (
+ not self.headers or "Content-Type" not in self.headers
+ ):
headers["Content-Type"] = self.content_type
+
+ # Extend headers if they exist
if self.headers:
headers.extend(self.headers)
+
return headers
def get_response(self, request: "PreparedRequest") -> HTTPResponse:
@@ -503,23 +505,33 @@ class BaseResponse(object):
return True, ""
+ @property
+ def call_count(self) -> int:
+ return len(self._calls)
+
+ @property
+ def calls(self) -> CallList:
+ return self._calls
+
def _form_response(
body: Union[BufferedReader, BytesIO],
headers: Optional[Mapping[str, str]],
status: int,
) -> HTTPResponse:
- # The requests library's cookie handling depends on the response object
- # having an original response object with the headers as the `msg`, so
- # we give it what it needs.
- data = BytesIO()
- data.close()
-
- orig_response = HTTPResponse(
- body=data, # required to avoid "ValueError: Unable to determine whether fp is closed."
- msg=headers,
- preload_content=False,
- )
+ dummy_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ orig_response = http.client.HTTPResponse(sock=dummy_socket)
+ """
+ The cookie handling functionality of the `requests` library relies on the response object
+ having an original response object with the headers stored in the `msg` attribute.
+ Instead of supplying a file-like object of type `HTTPMessage` for the headers, we provide
+ the headers directly. This approach eliminates the need to parse the headers into a file-like
+ object and then rely on the library to unparse it back. These additional conversions can
+ introduce potential errors.
+ Therefore, we intentionally ignore type checking for this assignment.
+ """
+ orig_response.msg = headers # type: ignore[assignment]
+
return HTTPResponse(
status=status,
reason=client.responses.get(status, None),
@@ -534,8 +546,8 @@ class Response(BaseResponse):
def __init__(
self,
method: str,
- url: _URLPatternType,
- body: _Body = "",
+ url: "_URLPatternType",
+ body: "_Body" = "",
json: Optional[Any] = None,
status: int = 200,
headers: Optional[Mapping[str, str]] = None,
@@ -558,7 +570,7 @@ class Response(BaseResponse):
else:
content_type = "text/plain"
- self.body: _Body = body
+ self.body: "_Body" = body
self.status: int = status
self.headers: Optional[Mapping[str, str]] = headers
@@ -610,7 +622,7 @@ class CallbackResponse(BaseResponse):
def __init__(
self,
method: str,
- url: _URLPatternType,
+ url: "_URLPatternType",
callback: Callable[[Any], Any],
stream: Optional[bool] = None,
content_type: Optional[str] = "text/plain",
@@ -662,7 +674,7 @@ class PassthroughResponse(BaseResponse):
super().__init__(*args, passthrough=True, **kwargs)
-class RequestsMock(object):
+class RequestsMock:
DELETE: Literal["DELETE"] = "DELETE"
GET: Literal["GET"] = "GET"
HEAD: Literal["HEAD"] = "HEAD"
@@ -680,6 +692,8 @@ class RequestsMock(object):
passthru_prefixes: Tuple[str, ...] = (),
target: str = "requests.adapters.HTTPAdapter.send",
registry: Type[FirstMatchRegistry] = FirstMatchRegistry,
+ *,
+ real_adapter_send: "_HTTPAdapterSend" = _real_send,
) -> None:
self._calls: CallList = CallList()
self.reset()
@@ -690,6 +704,7 @@ class RequestsMock(object):
self.target: str = target
self._patcher: Optional["_mock_patcher[Any]"] = None
self._thread_lock = _ThreadingLock()
+ self._real_send = real_adapter_send
def get_registry(self) -> FirstMatchRegistry:
"""Returns current registry instance with responses.
@@ -728,10 +743,10 @@ class RequestsMock(object):
def add(
self,
- method: _HTTPMethodOrResponse = None,
+ method: "_HTTPMethodOrResponse" = None,
url: "Optional[_URLPatternType]" = None,
- body: _Body = "",
- adding_headers: _HeaderSet = None,
+ body: "_Body" = "",
+ adding_headers: "_HeaderSet" = None,
*args: Any,
**kwargs: Any,
) -> BaseResponse:
@@ -792,7 +807,7 @@ class RequestsMock(object):
def _parse_response_file(
self, file_path: "Union[str, bytes, os.PathLike[Any]]"
) -> "Dict[str, Any]":
- with open(file_path, "r") as file:
+ with open(file_path) as file:
data = yaml.safe_load(file)
return data
@@ -810,7 +825,7 @@ class RequestsMock(object):
auto_calculate_content_length=rsp["auto_calculate_content_length"],
)
- def add_passthru(self, prefix: _URLPatternType) -> None:
+ def add_passthru(self, prefix: "_URLPatternType") -> None:
"""
Register a URL prefix or regex to passthru any non-matching mock requests to.
@@ -831,7 +846,7 @@ class RequestsMock(object):
def remove(
self,
- method_or_response: _HTTPMethodOrResponse = None,
+ method_or_response: "_HTTPMethodOrResponse" = None,
url: "Optional[_URLPatternType]" = None,
) -> List[BaseResponse]:
"""
@@ -854,9 +869,9 @@ class RequestsMock(object):
def replace(
self,
- method_or_response: _HTTPMethodOrResponse = None,
+ method_or_response: "_HTTPMethodOrResponse" = None,
url: "Optional[_URLPatternType]" = None,
- body: _Body = "",
+ body: "_Body" = "",
*args: Any,
**kwargs: Any,
) -> BaseResponse:
@@ -880,9 +895,9 @@ class RequestsMock(object):
def upsert(
self,
- method_or_response: _HTTPMethodOrResponse = None,
+ method_or_response: "_HTTPMethodOrResponse" = None,
url: "Optional[_URLPatternType]" = None,
- body: _Body = "",
+ body: "_Body" = "",
*args: Any,
**kwargs: Any,
) -> BaseResponse:
@@ -903,9 +918,10 @@ class RequestsMock(object):
def add_callback(
self,
method: str,
- url: _URLPatternType,
+ url: "_URLPatternType",
callback: Callable[
- ["PreparedRequest"], Union[Exception, Tuple[int, Mapping[str, str], _Body]]
+ ["PreparedRequest"],
+ Union[Exception, Tuple[int, Mapping[str, str], "_Body"]],
],
match_querystring: Union[bool, FalseBool] = FalseBool(),
content_type: Optional[str] = "text/plain",
@@ -941,34 +957,17 @@ class RequestsMock(object):
self.reset()
return success
- @overload
- def activate(self, func: _F = ...) -> _F:
- """Overload for scenario when 'responses.activate' is used."""
-
- @overload
- def activate(
- self,
- *,
- registry: Type[Any] = ...,
- assert_all_requests_are_fired: bool = ...,
- ) -> Callable[["_F"], "_F"]:
- """Overload for scenario when
- 'responses.activate(registry=, assert_all_requests_are_fired=True)' is used.
-
- See https://github.com/getsentry/responses/pull/469 for more details
- """
-
def activate(
self,
- func: Optional[_F] = None,
+ func: Optional["_F"] = None,
*,
registry: Optional[Type[Any]] = None,
assert_all_requests_are_fired: bool = False,
- ) -> Union[Callable[["_F"], "_F"], _F]:
+ ) -> Union[Callable[["_F"], "_F"], "_F"]:
if func is not None:
return get_wrapped(func, self)
- def deco_activate(function: _F) -> Callable[..., Any]:
+ def deco_activate(function: "_F") -> Callable[..., Any]:
return get_wrapped(
function,
self,
@@ -1030,7 +1029,7 @@ class RequestsMock(object):
]
):
logger.info("request.allowed-passthru", extra={"url": request_url})
- return _real_send(adapter, request, **kwargs)
+ return self._real_send(adapter, request, **kwargs) # type: ignore
error_msg = (
"Connection refused by Responses - the call doesn't "
@@ -1047,7 +1046,7 @@ class RequestsMock(object):
if self.passthru_prefixes:
error_msg += "Passthru prefixes:\n"
for p in self.passthru_prefixes:
- error_msg += "- {}\n".format(p)
+ error_msg += f"- {p}\n"
response = ConnectionError(error_msg)
response.request = request
@@ -1057,25 +1056,27 @@ class RequestsMock(object):
if match.passthrough:
logger.info("request.passthrough-response", extra={"url": request_url})
- response = _real_send(adapter, request, **kwargs) # type: ignore[assignment]
+ response = self._real_send(adapter, request, **kwargs) # type: ignore
else:
try:
response = adapter.build_response( # type: ignore[no-untyped-call]
request, match.get_response(request)
)
except BaseException as response:
- match.call_count += 1
- self._calls.add(request, response)
+ call = Call(request, response)
+ self._calls.add_call(call)
+ match.calls.add_call(call)
raise
if resp_callback:
response = resp_callback(response) # type: ignore[misc]
- match.call_count += 1
- self._calls.add(request, response) # type: ignore[misc]
+ call = Call(request, response) # type: ignore[misc]
+ self._calls.add_call(call)
+ match.calls.add_call(call)
retries = retries or adapter.max_retries
# first validate that current request is eligible to be retried.
- # See ``requests.packages.urllib3.util.retry.Retry`` documentation.
+ # See ``urllib3.util.retry.Retry`` documentation.
if retries.is_retry(
method=response.request.method, status_code=response.status_code # type: ignore[misc]
):
@@ -1156,7 +1157,7 @@ class RequestsMock(object):
not_called = [m for m in self.registered() if m.call_count == 0]
if not_called:
raise AssertionError(
- "Not all requests have been executed {0!r}".format(
+ "Not all requests have been executed {!r}".format(
[(match.method, match.url) for match in not_called]
)
)
diff --git a/contrib/python/responses/py3/responses/matchers.py b/contrib/python/responses/py3/responses/matchers.py
index 4880e5082e..175f967035 100644
--- a/contrib/python/responses/py3/responses/matchers.py
+++ b/contrib/python/responses/py3/responses/matchers.py
@@ -1,4 +1,6 @@
+import gzip
import json as json_module
+import re
from json.decoder import JSONDecodeError
from typing import Any
from typing import Callable
@@ -11,7 +13,7 @@ from urllib.parse import parse_qsl
from urllib.parse import urlparse
from requests import PreparedRequest
-from requests.packages.urllib3.util.url import parse_url
+from urllib3.util.url import parse_url
def _create_key_val_str(input_dict: Union[Dict[Any, Any], Any]) -> str:
@@ -47,7 +49,7 @@ def _create_key_val_str(input_dict: Union[Dict[Any, Any], Any]) -> str:
elif isinstance(val, list):
val = list_to_str(input_list=val)
- items_list.append("{}: {}".format(key, val))
+ items_list.append(f"{key}: {val}")
key_val_str = "{{{}}}".format(", ".join(items_list))
return key_val_str
@@ -124,8 +126,11 @@ def json_params_matcher(
request_body = request.body
json_params = (params or {}) if not isinstance(params, list) else params
try:
- if isinstance(request_body, bytes):
- request_body = request_body.decode("utf-8")
+ if isinstance(request.body, bytes):
+ try:
+ request_body = request.body.decode("utf-8")
+ except UnicodeDecodeError:
+ request_body = gzip.decompress(request.body).decode("utf-8")
json_body = json_module.loads(request_body) if request_body else {}
if (
@@ -251,7 +256,7 @@ def query_string_matcher(query: Optional[str]) -> Callable[..., Any]:
def match(request: PreparedRequest) -> Tuple[bool, str]:
reason = ""
- data = parse_url(request.url)
+ data = parse_url(request.url or "")
request_query = data.query
request_qsl = sorted(parse_qsl(request_query)) if request_query else {}
@@ -402,6 +407,23 @@ def header_matcher(
:return: (func) matcher
"""
+ def _compare_with_regex(request_headers: Union[Dict[Any, Any], Any]) -> bool:
+ if strict_match and len(request_headers) != len(headers):
+ return False
+
+ for k, v in headers.items():
+ if request_headers.get(k) is not None:
+ if isinstance(v, re.Pattern):
+ if re.match(v, request_headers[k]) is None:
+ return False
+ else:
+ if not v == request_headers[k]:
+ return False
+ elif strict_match:
+ return False
+
+ return True
+
def match(request: PreparedRequest) -> Tuple[bool, str]:
request_headers: Union[Dict[Any, Any], Any] = request.headers or {}
@@ -409,7 +431,7 @@ def header_matcher(
# filter down to just the headers specified in the matcher
request_headers = {k: v for k, v in request_headers.items() if k in headers}
- valid = sorted(headers.items()) == sorted(request_headers.items())
+ valid = _compare_with_regex(request_headers)
if not valid:
return False, "Headers do not match: {} doesn't match {}".format(
diff --git a/contrib/python/responses/py3/responses/registries.py b/contrib/python/responses/py3/responses/registries.py
index 4b7e2337e6..fcf481a880 100644
--- a/contrib/python/responses/py3/responses/registries.py
+++ b/contrib/python/responses/py3/responses/registries.py
@@ -11,7 +11,7 @@ if TYPE_CHECKING: # pragma: no cover
from responses import BaseResponse
-class FirstMatchRegistry(object):
+class FirstMatchRegistry:
def __init__(self) -> None:
self._responses: List["BaseResponse"] = []
@@ -67,9 +67,7 @@ class FirstMatchRegistry(object):
try:
index = self.registered.index(response)
except ValueError:
- raise ValueError(
- "Response is not registered for URL {}".format(response.url)
- )
+ raise ValueError(f"Response is not registered for URL {response.url}")
self.registered[index] = response
return response
diff --git a/contrib/python/responses/py3/ya.make b/contrib/python/responses/py3/ya.make
index 20cb7a76c8..bd363a36d8 100644
--- a/contrib/python/responses/py3/ya.make
+++ b/contrib/python/responses/py3/ya.make
@@ -2,14 +2,13 @@
PY3_LIBRARY()
-VERSION(0.23.3)
+VERSION(0.24.0)
LICENSE(Apache-2.0)
PEERDIR(
contrib/python/PyYAML
contrib/python/requests
- contrib/python/types-PyYAML
contrib/python/urllib3
)
diff --git a/contrib/python/types-PyYAML/.dist-info/METADATA b/contrib/python/types-PyYAML/.dist-info/METADATA
deleted file mode 100644
index 1805257c6b..0000000000
--- a/contrib/python/types-PyYAML/.dist-info/METADATA
+++ /dev/null
@@ -1,31 +0,0 @@
-Metadata-Version: 2.1
-Name: types-PyYAML
-Version: 6.0.12.12
-Summary: Typing stubs for PyYAML
-Home-page: https://github.com/python/typeshed
-License: Apache-2.0 license
-Project-URL: GitHub, https://github.com/python/typeshed
-Project-URL: Changes, https://github.com/typeshed-internal/stub_uploader/blob/main/data/changelogs/PyYAML.md
-Project-URL: Issue tracker, https://github.com/python/typeshed/issues
-Project-URL: Chat, https://gitter.im/python/typing
-Classifier: License :: OSI Approved :: Apache Software License
-Classifier: Programming Language :: Python :: 3
-Classifier: Typing :: Stubs Only
-Description-Content-Type: text/markdown
-
-## Typing stubs for PyYAML
-
-This is a PEP 561 type stub package for the `PyYAML` package. It
-can be used by type-checking tools like
-[mypy](https://github.com/python/mypy/),
-[pyright](https://github.com/microsoft/pyright),
-[pytype](https://github.com/google/pytype/),
-PyCharm, etc. to check code that uses
-`PyYAML`. The source for this package can be found at
-https://github.com/python/typeshed/tree/main/stubs/PyYAML. All fixes for
-types and metadata should be contributed there.
-
-See https://github.com/python/typeshed/blob/main/README.md for more details.
-This package was generated from typeshed commit `e40b5be2ea48dc83ffc2f38bfd542334deb98b20` and was tested
-with mypy 1.5.1, pyright 1.1.328, and
-pytype 2023.8.31.
diff --git a/contrib/python/types-PyYAML/.dist-info/top_level.txt b/contrib/python/types-PyYAML/.dist-info/top_level.txt
deleted file mode 100644
index 06a155d8c8..0000000000
--- a/contrib/python/types-PyYAML/.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-yaml-stubs
diff --git a/contrib/python/types-PyYAML/ya.make b/contrib/python/types-PyYAML/ya.make
deleted file mode 100644
index 144b1c420f..0000000000
--- a/contrib/python/types-PyYAML/ya.make
+++ /dev/null
@@ -1,40 +0,0 @@
-# Generated by devtools/yamaker (pypi).
-
-PY3_LIBRARY()
-
-VERSION(6.0.12.12)
-
-LICENSE(Apache-2.0)
-
-NO_LINT()
-
-PY_SRCS(
- TOP_LEVEL
- yaml-stubs/__init__.pyi
- yaml-stubs/_yaml.pyi
- yaml-stubs/composer.pyi
- yaml-stubs/constructor.pyi
- yaml-stubs/cyaml.pyi
- yaml-stubs/dumper.pyi
- yaml-stubs/emitter.pyi
- yaml-stubs/error.pyi
- yaml-stubs/events.pyi
- yaml-stubs/loader.pyi
- yaml-stubs/nodes.pyi
- yaml-stubs/parser.pyi
- yaml-stubs/reader.pyi
- yaml-stubs/representer.pyi
- yaml-stubs/resolver.pyi
- yaml-stubs/scanner.pyi
- yaml-stubs/serializer.pyi
- yaml-stubs/tokens.pyi
-)
-
-RESOURCE_FILES(
- PREFIX contrib/python/types-PyYAML/
- .dist-info/METADATA
- .dist-info/top_level.txt
- yaml-stubs/METADATA.toml
-)
-
-END()
diff --git a/contrib/python/types-PyYAML/yaml-stubs/METADATA.toml b/contrib/python/types-PyYAML/yaml-stubs/METADATA.toml
deleted file mode 100644
index c31b588e64..0000000000
--- a/contrib/python/types-PyYAML/yaml-stubs/METADATA.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-version = "6.0.*"
-upstream_repository = "https://github.com/yaml/pyyaml"