Compare commits

..

18 Commits

Author SHA1 Message Date
Nate Prewitt
b7b549b545 v2.34.1
Some checks failed
Publish to PyPI / Build dists (push) Has been cancelled
Publish to PyPI / Publish (push) Has been cancelled
Publish to PyPI / Publish to Test PyPI (push) Has been cancelled
Tests / build (macOS-latest, 3.10) (push) Has been cancelled
Tests / build (macOS-latest, 3.11) (push) Has been cancelled
Tests / build (macOS-latest, 3.12) (push) Has been cancelled
Tests / build (macOS-latest, 3.13) (push) Has been cancelled
Tests / build (macOS-latest, 3.14) (push) Has been cancelled
Tests / build (macOS-latest, 3.14t) (push) Has been cancelled
Tests / build (macOS-latest, 3.15-dev) (push) Has been cancelled
Tests / build (macOS-latest, pypy-3.11) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.10) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.11) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.12) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.13) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.14) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.14t) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.15-dev) (push) Has been cancelled
Tests / build (ubuntu-22.04, pypy-3.11) (push) Has been cancelled
Tests / build (windows-latest, 3.10) (push) Has been cancelled
Tests / build (windows-latest, 3.11) (push) Has been cancelled
Tests / build (windows-latest, 3.12) (push) Has been cancelled
Tests / build (windows-latest, 3.13) (push) Has been cancelled
Tests / build (windows-latest, 3.14) (push) Has been cancelled
Tests / build (windows-latest, 3.14t) (push) Has been cancelled
Tests / build (windows-latest, 3.15-dev) (push) Has been cancelled
Tests / No Character Detection (push) Has been cancelled
Tests / urllib3 1.x (push) Has been cancelled
Type Check / typecheck (3.10) (push) Has been cancelled
Type Check / typecheck (3.14) (push) Has been cancelled
2026-05-13 12:17:24 -07:00
Nate Prewitt
e511bc7277 Fix mutability issues with headers input types (#7431) 2026-05-13 12:16:50 -07:00
Nate Prewitt
5691f59613 Update JsonType containers to read-based collections (#7436) 2026-05-13 08:43:16 -06:00
Nate Prewitt
2144213c30 Constrain Response.reason to str (#7437) 2026-05-13 08:42:42 -06:00
Kaeun Kim
6404f345e5 Fix prepare_body stream detection for __getattr__-based file wrappers (#7433)
---------

Co-authored-by: Nate Prewitt <nate.prewitt@gmail.com>
2026-05-12 10:51:01 -07:00
Nate Prewitt
0b401c76b6 v2.34.0
Some checks failed
Publish to PyPI / Build dists (push) Has been cancelled
Publish to PyPI / Publish (push) Has been cancelled
Publish to PyPI / Publish to Test PyPI (push) Has been cancelled
Tests / build (macOS-latest, 3.10) (push) Has been cancelled
Tests / build (macOS-latest, 3.11) (push) Has been cancelled
Tests / build (macOS-latest, 3.12) (push) Has been cancelled
Tests / build (macOS-latest, 3.13) (push) Has been cancelled
Tests / build (macOS-latest, 3.14) (push) Has been cancelled
Tests / build (macOS-latest, 3.14t) (push) Has been cancelled
Tests / build (macOS-latest, 3.15-dev) (push) Has been cancelled
Tests / build (macOS-latest, pypy-3.11) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.10) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.11) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.12) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.13) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.14) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.14t) (push) Has been cancelled
Tests / build (ubuntu-22.04, 3.15-dev) (push) Has been cancelled
Tests / build (ubuntu-22.04, pypy-3.11) (push) Has been cancelled
Tests / build (windows-latest, 3.10) (push) Has been cancelled
Tests / build (windows-latest, 3.11) (push) Has been cancelled
Tests / build (windows-latest, 3.12) (push) Has been cancelled
Tests / build (windows-latest, 3.13) (push) Has been cancelled
Tests / build (windows-latest, 3.14) (push) Has been cancelled
Tests / build (windows-latest, 3.14t) (push) Has been cancelled
Tests / build (windows-latest, 3.15-dev) (push) Has been cancelled
Tests / No Character Detection (push) Has been cancelled
Tests / urllib3 1.x (push) Has been cancelled
Type Check / typecheck (3.10) (push) Has been cancelled
Type Check / typecheck (3.14) (push) Has been cancelled
2026-05-11 12:24:57 -07:00
Nate Prewitt
86b378d3f6 Align Session.get parameters with requests.get (#7429) 2026-05-11 12:24:34 -07:00
Nate Prewitt
a4f9a5999b Port bpo-39057 to Requests (#7427) 2026-05-11 12:24:21 -07:00
Nate Prewitt
3816cfa1ab Parameterize SupportsItems to handle Mapping key invariance (#7426) 2026-05-11 10:33:17 -07:00
Sebastian Meyer
b684dcb9bb sessions: fix hooks type (#7425) 2026-05-11 09:14:13 -07:00
Nate Prewitt
dc9dbdfb34 Formalize 3.15 support (#7422) 2026-05-10 19:05:34 -07:00
Nate Prewitt
25340ebad0 Clear proxy env vars before every test run (#7423) 2026-05-10 19:05:15 -07:00
typhon8
fd628095d7 Preserve leading slashes in request path_url (#7315)
---------

Co-authored-by: Nate Prewitt <nate.prewitt@gmail.com>
2026-05-10 14:41:25 -07:00
eggsort
e8d2c015ee docs: Fix missing hook output in docs example (#7421) 2026-05-09 12:51:50 -06:00
Nate Prewitt
eb173bc819 Add 3.14t support to CI (#7419) 2026-05-08 13:18:00 -07:00
Nate Prewitt
d60f4773b1 Cleanup remaining http:// reference URIs 2026-05-07 16:27:46 -06:00
Joshua Kothapalle
f64a0d782b docs: update stale Sphinx link in contributing guide 2026-05-07 16:27:46 -06:00
dependabot[bot]
04d750509b Bump https://github.com/astral-sh/ruff-pre-commit (#7411)
Bumps the pre-commit group with 1 update: [https://github.com/astral-sh/ruff-pre-commit](https://github.com/astral-sh/ruff-pre-commit).


Updates `https://github.com/astral-sh/ruff-pre-commit` from v0.15.11 to 0.15.12
- [Release notes](https://github.com/astral-sh/ruff-pre-commit/releases)
- [Commits](https://github.com/astral-sh/ruff-pre-commit/compare/v0.15.11...v0.15.12)

---
updated-dependencies:
- dependency-name: https://github.com/astral-sh/ruff-pre-commit
  dependency-version: 0.15.12
  dependency-type: direct:production
  dependency-group: pre-commit
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-04 14:42:06 -07:00
20 changed files with 142 additions and 49 deletions

View File

@@ -8,12 +8,11 @@ permissions:
jobs:
build:
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.python-version == '3.15-dev' }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.15-dev", "pypy-3.11"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.14t", "3.15-dev", "pypy-3.11"]
os: [ubuntu-22.04, macOS-latest, windows-latest]
# Pypy-3.11 can't install openssl-sys with rust
# which prevents us from testing in GHA.

View File

@@ -13,7 +13,7 @@ repos:
args: [--fix=auto]
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.11
rev: v0.15.12
hooks:
- id: ruff-check
args: [--fix]

View File

@@ -6,19 +6,48 @@ dev
- \[Short description of non-trivial change.\]
2.34.0 (2026-05-??)
2.34.1 (2026-05-13)
-------------------
**Improvements**
* Requests 2.34.0 introduces inline types, replacing those provided by
**Bugfixes**
- Widened `json` input type from `dict` and `list` to `Mapping`
and `Sequence`. (#7436)
- Changed `headers` input type to MutableMapping and removed `None` from
`Request.headers` typing to improve handling for users. (#7431)
- `Response.reason` moved from `str | None` to `str` to improve handling
for users. (#7437)
- Fixed a bug where some bodies with custom `__getattr__` implementations
weren't being properly detected as Iterables. (#7433)
2.34.0 (2026-05-11)
-------------------
**Announcements**
- Requests 2.34.0 introduces inline types, replacing those provided by
typeshed. Public API types should be fully compatible with mypy, pyright,
and ty. (#7272)
* Digest Auth hashing algorithms have added `usedforsecurity=False` to clarify
and ty. We believe types are comprehensive but if you find issues, please
report them to the pinned tracking issue.
Special thanks to @bastimeyer, @cthoyt, @edgarrmondragon, and @srittau for
helping review and test the types ahead of the release. (#7272)
**Improvements**
- Digest Auth hashing algorithms have added `usedforsecurity=False` to clarify
security considerations. (#7310)
- Requests added support for Python 3.15 based on beta1. Downstream projects
should be able to start testing prior to its release in October. (#7422)
- Requests added support for Python 3.14t. (#7419)
**Bugfixes**
* ``Response.history`` no longer contains a reference to itself, preventing
- ``Response.history`` no longer contains a reference to itself, preventing
accidental looping when traversing the history list. (#7328)
- Requests no longer performs greedy matching on no_proxy domains. The
proxy_bypass implementation has been updated with CPython's fix from
bpo-39057. (#7427)
- Requests no longer incorrectly strips duplicate leading slashes in
URI paths. This should address user issues with specific presigned
URLs. Note the full fix requires urllib3 2.7.0+. (#7315)
2.33.1 (2026-03-30)

View File

@@ -9,7 +9,7 @@ BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from https://www.sphinx-doc.org/)
endif
# Internal variables.

View File

@@ -30,7 +30,7 @@ Why not Httplib2?
-----------------
Chris Adams gave an excellent summary on
`Hacker News <http://news.ycombinator.com/item?id=2884406>`_:
`Hacker News <https://news.ycombinator.com/item?id=2884406>`_:
httplib2 is part of why you should use requests: it's far more respectable
as a client but not as well documented and it still takes way too much code
@@ -44,7 +44,7 @@ Chris Adams gave an excellent summary on
Disclosure: I'm listed in the requests AUTHORS file but can claim credit
for, oh, about 0.0001% of the awesomeness.
1. http://code.google.com/p/httplib2/issues/detail?id=96 is a good example:
1. https://code.google.com/p/httplib2/issues/detail?id=96 is a good example:
an annoying bug that affected many people, there was a fix available for
months, which worked great when I applied it in a fork and pounded a couple
TB of data through it, but it took over a year to make it into trunk and

View File

@@ -7,4 +7,4 @@ Articles & Talks
- `Issac Kelly's 'Consuming Web APIs' talk <https://issackelly.github.io/Consuming-Web-APIs-with-Python-Talk/slides/slides.html>`_
- `Blog post about Requests via Yum <https://arunsag.wordpress.com/2011/08/17/new-package-python-requests-http-for-humans/>`_
- `Russian blog post introducing Requests <https://habr.com/post/126262/>`_
- `Sending JSON in Requests <http://www.coglib.com/~icordasc/blog/2014/11/sending-json-in-requests.html>`_
- `Sending JSON in Requests <https://www.coglib.com/~icordasc/blog/2014/11/sending-json-in-requests.html>`_

View File

@@ -14,7 +14,7 @@ getting a feel for how contributing to this project works. If you have any
questions, feel free to reach out to either `Nate Prewitt`_, `Ian Cordasco`_,
or `Seth Michael Larson`_, the primary maintainers.
.. _Ian Cordasco: http://www.coglib.com/~icordasc/
.. _Ian Cordasco: https://www.coglib.com/~icordasc/
.. _Nate Prewitt: https://www.nateprewitt.com/
.. _Seth Michael Larson: https://sethmlarson.dev/
@@ -132,8 +132,8 @@ files and a semi-formal, yet friendly and approachable, prose style.
When presenting Python code, use single-quoted strings (``'hello'`` instead of
``"hello"``).
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
.. _Sphinx: http://sphinx-doc.org/index.html
.. _reStructuredText: https://docutils.sourceforge.net/rst.html
.. _Sphinx: https://www.sphinx-doc.org/en/master/
.. _bug-reports:

View File

@@ -65,7 +65,7 @@ if errorlevel 9009 (
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
echo.https://www.sphinx-doc.org/
exit /b 1
)

View File

@@ -467,6 +467,7 @@ Let's print some request method arguments at runtime::
You can add multiple hooks to a single request. Let's call two hooks at once::
>>> r = requests.get('https://httpbin.org/', hooks={'response': [print_url, record_hook]})
https://httpbin.org/
>>> r.hook_called
True

View File

@@ -37,9 +37,11 @@ classifiers = [
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Programming Language :: Python :: Free Threading :: 2 - Beta",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Software Development :: Libraries"
]

View File

@@ -5,8 +5,8 @@
__title__ = "requests"
__description__ = "Python HTTP for Humans."
__url__ = "https://requests.readthedocs.io"
__version__ = "2.34.0.dev1"
__build__ = 0x023400
__version__ = "2.34.1"
__build__ = 0x023401
__author__ = "Kenneth Reitz"
__author_email__ = "me@kennethreitz.org"
__license__ = "Apache-2.0"

View File

@@ -9,7 +9,7 @@ by external code.
from __future__ import annotations
from collections.abc import Callable, Iterable, Mapping, MutableMapping
from collections.abc import Callable, Iterable, Mapping, MutableMapping, Sequence
from typing import (
TYPE_CHECKING,
Any,
@@ -20,6 +20,8 @@ from typing import (
)
_T_co = TypeVar("_T_co", covariant=True)
_KT_co = TypeVar("_KT_co", covariant=True)
_VT_co = TypeVar("_VT_co", covariant=True)
@runtime_checkable
@@ -28,8 +30,8 @@ class SupportsRead(Protocol[_T_co]):
@runtime_checkable
class SupportsItems(Protocol):
def items(self) -> Iterable[tuple[Any, Any]]: ...
class SupportsItems(Protocol[_KT_co, _VT_co]):
def items(self) -> Iterable[tuple[_KT_co, _VT_co]]: ...
# These are needed at runtime for default_hooks() return type
@@ -79,7 +81,7 @@ if TYPE_CHECKING:
str | bytes | int | float | Iterable[str | bytes | int | float] | None
)
ParamsType: TypeAlias = (
Mapping[_ParamsMappingKeyType, _ParamsMappingValueType]
SupportsItems[_ParamsMappingKeyType, _ParamsMappingValueType]
| tuple[tuple[_ParamsMappingKeyType, _ParamsMappingValueType], ...]
| Iterable[tuple[_ParamsMappingKeyType, _ParamsMappingValueType]]
| str
@@ -87,7 +89,7 @@ if TYPE_CHECKING:
| None
)
KVDataType: TypeAlias = Iterable[tuple[Any, Any]] | Mapping[Any, Any]
KVDataType: TypeAlias = Iterable[tuple[Any, Any]] | SupportsItems[Any, Any]
RawDataType: TypeAlias = KVDataType | str | bytes
StreamDataType: TypeAlias = SupportsRead[str | bytes]
@@ -107,8 +109,7 @@ if TYPE_CHECKING:
bytes | str | Iterable[bytes | str] | SupportsRead[bytes | str] | None
)
HeadersType: TypeAlias = CaseInsensitiveDict[str] | Mapping[str, str | bytes]
HeadersUpdateType: TypeAlias = Mapping[str, str | bytes | None]
HeadersType: TypeAlias = MutableMapping[str, str | bytes] | None
CookiesType: TypeAlias = RequestsCookieJar | Mapping[str, str]
@@ -137,20 +138,26 @@ if TYPE_CHECKING:
VerifyType: TypeAlias = bool | str
CertType: TypeAlias = str | tuple[str, str] | None
JsonType: TypeAlias = (
None | bool | int | float | str | list["JsonType"] | dict[str, "JsonType"]
None
| bool
| int
| float
| str
| Sequence["JsonType"]
| Mapping[str, "JsonType"]
)
# TypedDicts for Unpack kwargs (PEP 692)
class BaseRequestKwargs(TypedDict, total=False):
headers: Mapping[str, str | bytes] | None
headers: HeadersType
cookies: RequestsCookieJar | CookieJar | dict[str, str] | None
files: FilesType
auth: AuthType
timeout: TimeoutType
allow_redirects: bool
proxies: dict[str, str] | None
hooks: HooksType
hooks: HooksInputType | None
stream: bool | None
verify: VerifyType | None
cert: CertType

View File

@@ -590,8 +590,6 @@ class HTTPAdapter(BaseAdapter):
using_socks_proxy = proxy_scheme.startswith("socks")
url = request.path_url
if url.startswith("//"): # Don't confuse urllib3
url = f"/{url.lstrip('/')}"
if is_proxied_http_request and not using_socks_proxy:
url = urldefragauth(request.url)

View File

@@ -83,6 +83,7 @@ from .utils import (
)
if TYPE_CHECKING:
from collections.abc import MutableMapping
from http.cookiejar import CookieJar
from typing_extensions import Self
@@ -310,7 +311,7 @@ class Request(RequestHooksMixin):
method: str | None
url: _t.UriType | None
headers: CaseInsensitiveDict[str] | Mapping[str, str | bytes] | None
headers: MutableMapping[str, str | bytes]
files: _t.FilesType
data: _t.DataType
json: _t.JsonType
@@ -322,7 +323,7 @@ class Request(RequestHooksMixin):
self,
method: str | None = None,
url: _t.UriType | None = None,
headers: Mapping[str, str | bytes] | None = None,
headers: _t.HeadersType = None,
files: _t.FilesType = None,
data: _t.DataType = None,
params: _t.ParamsType = None,
@@ -596,9 +597,9 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
if not isinstance(body, bytes):
body = body.encode("utf-8")
if isinstance(data, Iterable) and not isinstance(
data, (str, bytes, list, tuple, Mapping)
):
# data that proxies attributes to underlying objects needs hasattr
is_iterable = isinstance(data, Iterable) or hasattr(data, "__iter__")
if is_iterable and not isinstance(data, (str, bytes, list, tuple, Mapping)):
try:
length = super_len(data)
except (TypeError, AttributeError, UnsupportedOperation):
@@ -741,7 +742,7 @@ class Response:
url: str
encoding: str | None
history: list[Response]
reason: str | None
reason: str
cookies: RequestsCookieJar
elapsed: datetime.timedelta
request: PreparedRequest
@@ -790,7 +791,7 @@ class Response:
self.history = []
#: Textual reason of responded HTTP Status, e.g. "Not Found" or "OK".
self.reason = None
self.reason = None # type: ignore[assignment]
#: A CookieJar of Cookies the server sent back.
self.cookies = cookiejar_from_dict({})

View File

@@ -560,14 +560,14 @@ class Session(SessionRedirectMixin):
url: _t.UriType,
params: _t.ParamsType = None,
data: _t.DataType = None,
headers: Mapping[str, str | bytes] | None = None,
headers: _t.HeadersType = None,
cookies: RequestsCookieJar | CookieJar | dict[str, str] | None = None,
files: _t.FilesType = None,
auth: _t.AuthType = None,
timeout: _t.TimeoutType = None,
allow_redirects: bool = True,
proxies: dict[str, str] | None = None,
hooks: _t.HooksType = None,
hooks: _t.HooksInputType | None = None,
stream: bool | None = None,
verify: _t.VerifyType | None = None,
cert: _t.CertType = None,
@@ -652,16 +652,23 @@ class Session(SessionRedirectMixin):
return resp
def get(self, url: _t.UriType, **kwargs: Unpack[_t.GetKwargs]) -> Response:
def get(
self,
url: _t.UriType,
params: _t.ParamsType = None,
**kwargs: Unpack[_t.GetKwargs],
) -> Response:
r"""Sends a GET request. Returns :class:`Response` object.
:param url: URL for the new :class:`Request` object.
:param params: (optional) Dictionary, list of tuples or bytes to send
in the query string for the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
kwargs.setdefault("allow_redirects", True)
return self.request("GET", url, **kwargs)
return self.request("GET", url, params=params, **kwargs)
def options(self, url: _t.UriType, **kwargs: Unpack[_t.RequestKwargs]) -> Response:
r"""Sends a OPTIONS request. Returns :class:`Response` object.

View File

@@ -147,7 +147,7 @@ if sys.platform == "win32":
def dict_to_sequence(
d: _t.SupportsItems | Iterable[tuple[Any, Any]],
d: _t.SupportsItems[Any, Any] | Iterable[tuple[Any, Any]],
) -> Iterable[tuple[Any, Any]]:
"""Returns an internal sequence dictionary update."""
@@ -371,10 +371,10 @@ def from_key_val_list(
def to_key_val_list(value: None) -> None: ...
@overload
def to_key_val_list(
value: Mapping[_KT, _VT] | Iterable[tuple[_KT, _VT]],
value: _t.SupportsItems[_KT, _VT] | Iterable[tuple[_KT, _VT]],
) -> list[tuple[_KT, _VT]]: ...
def to_key_val_list(
value: Mapping[_KT, _VT] | Iterable[tuple[_KT, _VT]] | None,
value: _t.SupportsItems[_KT, _VT] | Iterable[tuple[_KT, _VT]] | None,
) -> list[tuple[_KT, _VT]] | None:
"""Take an object and test to see if it can be represented as a
dictionary. If it can be, return a list of tuples, e.g.,
@@ -851,9 +851,11 @@ def should_bypass_proxies(url: str, no_proxy: str | None) -> bool:
host_with_port += f":{parsed.port}"
for host in no_proxy_hosts:
host = host.lstrip(".")
if hostname == host or host_with_port == host:
return True
host = "." + host
if hostname.endswith(host) or host_with_port.endswith(host):
# The URL does match something in no_proxy, so we don't want
# to apply the proxies on this URL.
return True
with set_environ("no_proxy", no_proxy_arg):

View File

@@ -22,6 +22,15 @@ def prepare_url(value):
return inner
@pytest.fixture(autouse=True)
def clean_proxy_environ(monkeypatch):
"""Remove proxy related environment variables for every test."""
proxy_vars = ("http_proxy", "https_proxy", "no_proxy", "ftp_proxy", "all_proxy")
for var in proxy_vars:
monkeypatch.delenv(var, raising=False)
monkeypatch.delenv(var.upper(), raising=False)
@pytest.fixture
def httpbin(httpbin):
return prepare_url(httpbin)

View File

@@ -1,8 +1,8 @@
import requests.adapters
def test_request_url_trims_leading_path_separators():
def test_request_url_handles_leading_path_separators():
"""See also https://github.com/psf/requests/issues/6643."""
a = requests.adapters.HTTPAdapter()
p = requests.Request(method="GET", url="http://127.0.0.1:10000//v:h").prepare()
assert "/v:h" == a.request_url(p, {})
assert "//v:h" == a.request_url(p, {})

View File

@@ -2073,6 +2073,21 @@ class TestRequests:
assert "Unable to rewind request body" in str(e)
def test_getattr_proxy_stream_follows_redirect(self, httpbin):
"""Ensure stream wrappers that don't implement __iter__ directly are still detected."""
class AttrProxy:
def __init__(self):
self._file = io.BytesIO(b"data")
def __getattr__(self, name):
return getattr(self._file, name)
r = requests.post(
httpbin("redirect-to?url=/post&status_code=307"), data=AttrProxy()
)
assert r.json()["data"] == "data"
def _patch_adapter_gzipped_redirect(self, session, url):
adapter = session.get_adapter(url=url)
org_build_response = adapter.build_response

View File

@@ -844,6 +844,29 @@ def test_should_bypass_proxies_no_proxy(url, expected, monkeypatch):
assert should_bypass_proxies(url, no_proxy=no_proxy) == expected
@pytest.mark.parametrize(
"url, expected",
(
("http://localhost/", True),
("http://anotherdomain.com:8888/", True),
("http://newdomain.com:1234/", True),
("http://www.newdomain.com:1234/", True),
("http://foo.d.o.t/", True),
("http://d.o.t/", True),
("http://prelocalhost/", False),
("http://newdomain.com/", False),
("http://newdomain.com:1235/", False),
),
)
def test_should_bypass_proxies_no_proxy_domain_boundary(url, expected):
"""Ensure no_proxy matching respects domain boundaries and does not
greedily match domains that merely endswith the no_proxy entry.
See CPython bpo-39057.
"""
no_proxy = "localhost, anotherdomain.com, newdomain.com:1234, .d.o.t"
assert should_bypass_proxies(url, no_proxy=no_proxy) == expected
@pytest.mark.skipif(os.name != "nt", reason="Test only on Windows")
@pytest.mark.parametrize(
"url, expected, override",