Skip to content

Bump requests from 2.32.4 to 2.33.0#172

Open
dependabot[bot] wants to merge 1 commit intomasterfrom
dependabot/pip/requests-2.33.0
Open

Bump requests from 2.32.4 to 2.33.0#172
dependabot[bot] wants to merge 1 commit intomasterfrom
dependabot/pip/requests-2.33.0

Conversation

@dependabot
Copy link
Copy Markdown
Contributor

@dependabot dependabot bot commented on behalf of github Mar 26, 2026

Bumps requests from 2.32.4 to 2.33.0.

Release notes

Sourced from requests's releases.

v2.33.0

2.33.0 (2026-03-25)

Announcements

  • 📣 Requests is adding inline types. If you have a typed code base that uses Requests, please take a look at #7271. Give it a try, and report any gaps or feedback you may have in the issue. 📣

Security

  • CVE-2026-25645 requests.utils.extract_zipped_paths now extracts contents to a non-deterministic location to prevent malicious file replacement. This does not affect default usage of Requests, only applications calling the utility function directly.

Improvements

  • Migrated to a PEP 517 build system using setuptools. (#7012)

Bugfixes

  • Fixed an issue where an empty netrc entry could cause malformed authentication to be applied to Requests on Python 3.11+. (#7205)

Deprecations

  • Dropped support for Python 3.9 following its end of support. (#7196)

Documentation

  • Various typo fixes and doc improvements.

New Contributors

Full Changelog: https://github.com/psf/requests/blob/main/HISTORY.md#2330-2026-03-25

v2.32.5

2.32.5 (2025-08-18)

Bugfixes

  • The SSLContext caching feature originally introduced in 2.32.0 has created a new class of issues in Requests that have had negative impact across a number of use cases. The Requests team has decided to revert this feature as long term maintenance of it is proving to be unsustainable in its current iteration.

Deprecations

  • Added support for Python 3.14.
  • Dropped support for Python 3.8 following its end of support.
Changelog

Sourced from requests's changelog.

2.33.0 (2026-03-25)

Announcements

  • 📣 Requests is adding inline types. If you have a typed code base that uses Requests, please take a look at #7271. Give it a try, and report any gaps or feedback you may have in the issue. 📣

Security

  • CVE-2026-25645 requests.utils.extract_zipped_paths now extracts contents to a non-deterministic location to prevent malicious file replacement. This does not affect default usage of Requests, only applications calling the utility function directly.

Improvements

  • Migrated to a PEP 517 build system using setuptools. (#7012)

Bugfixes

  • Fixed an issue where an empty netrc entry could cause malformed authentication to be applied to Requests on Python 3.11+. (#7205)

Deprecations

  • Dropped support for Python 3.9 following its end of support. (#7196)

Documentation

  • Various typo fixes and doc improvements.

2.32.5 (2025-08-18)

Bugfixes

  • The SSLContext caching feature originally introduced in 2.32.0 has created a new class of issues in Requests that have had negative impact across a number of use cases. The Requests team has decided to revert this feature as long term maintenance of it is proving to be unsustainable in its current iteration.

Deprecations

  • Added support for Python 3.14.
  • Dropped support for Python 3.8 following its end of support.
Commits
  • bc04dfd v2.33.0
  • 66d21cb Merge commit from fork
  • 8b9bc8f Move badges to top of README (#7293)
  • e331a28 Remove unused extraction call (#7292)
  • 753fd08 docs: fix FAQ grammar in httplib2 example
  • 774a0b8 docs(socks): same block as other sections
  • 9c72a41 Bump github/codeql-action from 4.33.0 to 4.34.1
  • ebf7190 Bump github/codeql-action from 4.32.0 to 4.33.0
  • 0e4ae38 docs: exclude Response.is_permanent_redirect from API docs (#7244)
  • d568f47 docs: clarify Quickstart POST example (#6960)
  • Additional commits viewable in compare view

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    You can disable automated security fix PRs for this repo from the Security Alerts page.

Bumps [requests](https://github.com/psf/requests) from 2.32.4 to 2.33.0.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](psf/requests@v2.32.4...v2.33.0)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.33.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot bot added dependencies Pull requests that update a dependency file python Pull requests that update python code labels Mar 26, 2026
@dependabot dependabot bot requested a review from porteron as a code owner March 26, 2026 16:29
@dependabot dependabot bot added dependencies Pull requests that update a dependency file python Pull requests that update python code labels Mar 26, 2026
@github-actions
Copy link
Copy Markdown

[puLL-Merge] - psf/requests@v2.32.4..v2.33.0

Diff
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000000..6cfdfe4b42
--- /dev/null
+++ .github/CODEOWNERS
@@ -0,0 +1,8 @@
+# Restrict all files related to deploying to
+# require lead maintainer approval.
+
+.github/workflows/            @nateprewitt @sigmavirus24
+.github/CODEOWNERS            @nateprewitt @sigmavirus24
+src/requests/__version__.py   @nateprewitt @sigmavirus24
+HISTORY.md                    @nateprewitt @sigmavirus24
+pyproject.toml                @nateprewitt @sigmavirus24
diff --git .github/workflows/codeql-analysis.yml .github/workflows/codeql-analysis.yml
index 170391ef09..59ae461954 100644
--- .github/workflows/codeql-analysis.yml
+++ .github/workflows/codeql-analysis.yml
@@ -32,7 +32,7 @@ jobs:
 
     steps:
     - name: Checkout repository
-      uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+      uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
       with:
         # We must fetch at least the immediate parents so that if this is
         # a pull request then we can checkout the head.
@@ -45,7 +45,7 @@ jobs:
 
     # Initializes the CodeQL tools for scanning.
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
+      uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
       with:
         languages: "python"
         # If you wish to specify custom queries, you can do so here or in a config file.
@@ -56,7 +56,7 @@ jobs:
     # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
     # If this step fails, then you should remove it and run the build manually (see below)
     - name: Autobuild
-      uses: github/codeql-action/autobuild@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
+      uses: github/codeql-action/autobuild@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
 
     # ℹ️ Command-line programs to run using the OS shell.
     # 📚 https://git.io/JvXDl
@@ -70,4 +70,4 @@ jobs:
     #   make release
 
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@f6091c0113d1dcf9b98e269ee48e8a7e51b7bdd4 # v3.28.5
+      uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v4.34.1
diff --git .github/workflows/lint.yml .github/workflows/lint.yml
index 52b1fe075e..e213b3b580 100644
--- .github/workflows/lint.yml
+++ .github/workflows/lint.yml
@@ -11,9 +11,9 @@ jobs:
     timeout-minutes: 10
 
     steps:
-    - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
     - name: Set up Python
-      uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
+      uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
       with:
         python-version: "3.x"
     - name: Run pre-commit
diff --git .github/workflows/lock-issues.yml .github/workflows/lock-issues.yml
index 7d5a3c6525..e8fe8a5cc2 100644
--- .github/workflows/lock-issues.yml
+++ .github/workflows/lock-issues.yml
@@ -13,7 +13,7 @@ jobs:
     if: github.repository_owner == 'psf'
     runs-on: ubuntu-latest
     steps:
-      - uses: dessant/lock-threads@d42e5f49803f3c4e14ffee0378e31481265dda22 # v5.0.0
+      - uses: dessant/lock-threads@7266a7ce5c1df01b1c6db85bf8cd86c737dadbe7 # v6.0.0
         with:
             issue-lock-inactive-days: 90
             pr-lock-inactive-days: 90
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000000..a44ac97210
--- /dev/null
+++ .github/workflows/publish.yml
@@ -0,0 +1,95 @@
+name: Publish to PyPI
+
+on:
+  push:
+    tags:
+      - "v*"
+  workflow_dispatch:
+    inputs:
+      test-pypi-only:
+        description: "Publish to Test PyPI only"
+        type: boolean
+        default: true
+
+permissions:
+  contents: read
+
+jobs:
+  build:
+    name: "Build dists"
+    runs-on: "ubuntu-latest"
+    outputs:
+      artifact-id: ${{ steps.upload-artifact.outputs.artifact-id }}
+
+    steps:
+      - name: "Checkout repository"
+        uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6.0.2
+        with:
+          persist-credentials: false
+
+      - name: "Setup Python"
+        uses: "actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405" # v6.2.0
+        with:
+          python-version: "3.x"
+
+      - name: "Install dependencies"
+        run: python -m pip install build==1.4.0
+
+      - name: "Build dists"
+        run: |
+          SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) \
+          python -m build
+
+      - name: "Upload dists"
+        uses: "actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f"
+        id: upload-artifact
+        with:
+          name: "dist"
+          path: "dist/"
+          if-no-files-found: error
+          retention-days: 5
+
+  publish:
+    name: "Publish"
+    if: startsWith(github.ref, 'refs/tags/')
+    needs: ["build"]
+    permissions:
+      id-token: write
+    runs-on: "ubuntu-latest"
+    environment:
+      name: "publish"
+
+    steps:
+    - name: "Download dists"
+      uses: "actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3" # v8.0.0
+      with:
+        artifact-ids: ${{ needs.build.outputs.artifact-id }}
+        path: "dist/"
+
+    - name: "Publish dists to PyPI"
+      uses: "pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e" # v1.13.0
+      with:
+        attestations: true
+
+  publish-test-pypi:
+    name: "Publish to Test PyPI"
+    if: github.event_name == 'workflow_dispatch'
+    needs: ["build"]
+    permissions:
+      id-token: write
+    runs-on: "ubuntu-latest"
+    environment:
+      name: "testpypi"
+
+    steps:
+    - name: "Download dists"
+      uses: "actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3" # v8.0.0
+      with:
+        artifact-ids: ${{ needs.build.outputs.artifact-id }}
+        path: "dist/"
+
+    - name: "Publish dists to Test PyPI"
+      uses: "pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e" # v1.13.0
+      with:
+        repository-url: https://test.pypi.org/legacy/
+        attestations: true
diff --git .github/workflows/run-tests.yml .github/workflows/run-tests.yml
index 052560153c..c9fd81005e 100644
--- .github/workflows/run-tests.yml
+++ .github/workflows/run-tests.yml
@@ -8,11 +8,12 @@ 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.8", "3.9", "3.10", "3.11", "3.12", "3.13", "pypy-3.10", "pypy-3.11"]
+        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14", "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.
@@ -20,14 +21,16 @@ jobs:
         - { python-version: "pypy-3.11", os: "windows-latest" }
 
     steps:
-    - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
+    - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
     - name: Set up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
+      uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
       with:
         python-version: ${{ matrix.python-version }}
         cache: 'pip'
         allow-prereleases: true
     - name: Install dependencies
+      env:
+        PYO3_USE_ABI3_FORWARD_COMPATIBILITY: ${{ matrix.python-version == '3.15-dev' && '1' || '' }}
       run: |
         make
     - name: Run tests
@@ -41,11 +44,11 @@ jobs:
       fail-fast: true
 
     steps:
-      - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
-      - name: 'Set up Python 3.8'
-        uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
+      - name: 'Set up Python 3.10'
+        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
         with:
-          python-version: '3.8'
+          python-version: '3.10'
       - name: Install dependencies
         run: |
           make
@@ -61,11 +64,11 @@ jobs:
       fail-fast: true
 
     steps:
-      - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938
-      - name: 'Set up Python 3.8'
-        uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
+      - name: 'Set up Python 3.10'
+        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
         with:
-          python-version: '3.8'
+          python-version: '3.10'
       - name: Install dependencies
         run: |
           make
diff --git .pre-commit-config.yaml .pre-commit-config.yaml
index 0a0515cf87..a5b623cc20 100644
--- .pre-commit-config.yaml
+++ .pre-commit-config.yaml
@@ -5,24 +5,12 @@ repos:
   rev: v4.4.0
   hooks:
   - id: check-yaml
-  - id: debug-statements
   - id: end-of-file-fixer
   - id: trailing-whitespace
-- repo: https://github.com/PyCQA/isort
-  rev: 5.12.0
+- repo: https://github.com/astral-sh/ruff-pre-commit
+  rev: v0.9.3
   hooks:
-    - id: isort
-- repo: https://github.com/psf/black
-  rev: 23.7.0
-  hooks:
-    - id: black
+    - id: ruff
+      args: [--fix]
+    - id: ruff-format
       exclude: tests/test_lowlevel.py
-- repo: https://github.com/asottile/pyupgrade
-  rev: v3.10.1
-  hooks:
-    - id: pyupgrade
-      args: [--py37-plus]
-- repo: https://github.com/PyCQA/flake8
-  rev: 6.1.0
-  hooks:
-    - id: flake8
diff --git AUTHORS.rst AUTHORS.rst
index 6e017c9a91..703a419a34 100644
--- AUTHORS.rst
+++ AUTHORS.rst
@@ -1,17 +1,17 @@
 Requests was lovingly created by Kenneth Reitz.
 
-Keepers of the Crystals
-```````````````````````
+Requests Maintainers
+````````````````````
 
+- Ian Stapleton Cordasco <graffatcolmingov@gmail.com> `@sigmavirus24 <https://github.com/sigmavirus24>`_.
 - Nate Prewitt `@nateprewitt <https://github.com/nateprewitt>`_.
-- Seth M. Larson `@sethmlarson <https://github.com/sethmlarson>`_.
 
-Previous Keepers of Crystals
-````````````````````````````
+Previous Maintainers
+````````````````````
+
 - Kenneth Reitz <me@kennethreitz.org> `@kennethreitz <https://github.com/kennethreitz>`_, reluctant Keeper of the Master Crystal.
 - Cory Benfield <cory@lukasa.co.uk> `@lukasa <https://github.com/lukasa>`_
-- Ian Cordasco <graffatcolmingov@gmail.com> `@sigmavirus24 <https://github.com/sigmavirus24>`_.
-
+- Seth M. Larson `@sethmlarson <https://github.com/sethmlarson>`_.
 
 Patches and Suggestions

diff --git HISTORY.md HISTORY.md
index ed4d652b1a..3c3d673f1a 100644
--- HISTORY.md
+++ HISTORY.md
@@ -6,6 +6,49 @@ dev

  • [Short description of non-trivial change.]

+2.33.0 (2026-03-25)
+--------------------
+
+Announcements
+- 📣 Requests is adding inline types. If you have a typed code base that
+uses Requests, please take a look at #7271. Give it a try, and report
+any gaps or feedback you may have in the issue. 📣
+
+Security
+- CVE-2026-25645 requests.utils.extract_zipped_paths now extracts

  • contents to a non-deterministic location to prevent malicious file
  • replacement. This does not affect default usage of Requests, only
  • applications calling the utility function directly.

+Improvements
+- Migrated to a PEP 517 build system using setuptools. (#7012)
+
+Bugfixes
+- Fixed an issue where an empty netrc entry could cause

  • malformed authentication to be applied to Requests on
  • Python 3.11+. (#7205)

+Deprecations
+- Dropped support for Python 3.9 following its end of support. (#7196)
+
+Documentation
+- Various typo fixes and doc improvements.
+
+
+2.32.5 (2025-08-18)
+-------------------
+
+Bugfixes
+
+- The SSLContext caching feature originally introduced in 2.32.0 has created

  • a new class of issues in Requests that have had negative impact across a number
  • of use cases. The Requests team has decided to revert this feature as long term
  • maintenance of it is proving to be unsustainable in its current iteration.

+Deprecations
+- Added support for Python 3.14.
+- Dropped support for Python 3.8 following its end of support.
+
2.32.4 (2025-06-10)

diff --git Makefile Makefile
index 6fa4152526..5401f406d5 100644
--- Makefile
+++ Makefile
@@ -2,17 +2,14 @@
init:
python -m pip install -r requirements-dev.txt
test:

  • This runs all of the tests on all supported Python versions.

  • tox -p
  • python -m pytest tests

ci:
python -m pytest tests --junitxml=report.xml

test-readme:
python setup.py check --restructuredtext --strict && ([ $$? -eq 0 ] && echo "README.rst and HISTORY.rst ok") || echo "Invalid markup in README.rst or HISTORY.rst!"

-flake8:

  • python -m flake8 src/requests

coverage:
python -m pytest --cov-config .coveragerc --verbose --cov-report term --cov-report xml --cov=src/requests tests

@@ -22,7 +19,7 @@ coverage:

publish: .publishenv
.publishenv/bin/python -m build

  • .publishenv/bin/python twine upload --skip-existing dist/*
  • .publishenv/bin/python -m twine upload --skip-existing dist/*
    rm -fr build dist .egg requests.egg-info

docs:
diff --git README.md README.md
index 79cf54d1e1..d960bee3d2 100644
--- README.md
+++ README.md
@@ -1,5 +1,10 @@

Requests

+Version
+Supported Versions
+Downloads
+Contributors
+
Requests is a simple, yet elegant, HTTP library.

@@ -21,10 +26,6 @@ Requests allows you to send HTTP/1.1 requests extremely easily. Theres no nee

Requests is one of the most downloaded Python packages today, pulling in around `30M downloads / week`according to GitHub, Requests is currently [depended upon](https://github.com/psf/requests/network/dependents?package_id=UGFja2FnZS01NzA4OTExNg%3D%3D) by `1,000,000+` repositories. You may certainly put your trust in this code.

-[![Downloads](https://static.pepy.tech/badge/requests/month)](https://pepy.tech/project/requests)
-[![Supported Versions](https://img.shields.io/pypi/pyversions/requests.svg)](https://pypi.org/project/requests)
-[![Contributors](https://img.shields.io/github/contributors/psf/requests.svg)](https://github.com/psf/requests/graphs/contributors)
-
## Installing Requests and Supported Versions

Requests is available on PyPI:
@@ -33,7 +34,7 @@ Requests is available on PyPI:
$ python -m pip install requests

-Requests officially supports Python 3.8+.
+Requests officially supports Python 3.10+.

Supported Features & Best–Practices

@@ -60,7 +61,7 @@ Requests is ready for the demands of building robust and reliable HTTP–speakin

Cloning the repository

When cloning the Requests repository, you may need to add the -c -fetch.fsck.badTimezone=ignore flag to avoid an error about a bad commit (see
+fetch.fsck.badTimezone=ignore` flag to avoid an error about a bad commit timestamp (see
this issue for more background):

diff --git docs/api.rst docs/api.rst
index 3ae5b9d856..47f31fa824 100644
--- docs/api.rst
+++ docs/api.rst
@@ -55,6 +55,7 @@ Lower-Level Classes

.. autoclass:: Response
   :inherited-members:
+   :exclude-members: is_permanent_redirect


Lower-Lower-Level Classes
diff --git docs/index.rst docs/index.rst
index 289250c2a4..aef47a8906 100644
--- docs/index.rst
+++ docs/index.rst
@@ -72,7 +72,7 @@ Requests is ready for today's web.
- Chunked Requests
- ``.netrc`` Support

-Requests officially supports Python 3.8+, and runs great on PyPy.
+Requests officially supports Python 3.9+, and runs great on PyPy.


The User Guide
diff --git pyproject.toml pyproject.toml
index 1b7901e155..dcde263dd8 100644
--- pyproject.toml
+++ pyproject.toml
@@ -1,7 +1,99 @@
-[tool.isort]
-profile = "black"
-src_paths = ["src/requests", "test"]
-honor_noqa = true
+[build-system]
+requires = ["setuptools>=61.0"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "requests"
+description = "Python HTTP for Humans."
+readme = "README.md"
+license = {text = "Apache-2.0"}
+authors = [
+    { name = "Kenneth Reitz", email = "me@kennethreitz.org" },
+]
+maintainers = [
+    {name = "Ian Stapleton Cordasco", email="graffatcolmingov@gmail.com"},
+    {name = "Nate Prewitt", email="nate.prewitt@gmail.com"}
+]
+requires-python = ">=3.10"
+dependencies = [
+    "charset_normalizer>=2,<4",
+    "idna>=2.5,<4",
+    "urllib3>=1.26,<3",
+    "certifi>=2023.5.7"
+]
+dynamic = ["version"]
+
+classifiers = [
+    "Development Status :: 5 - Production/Stable",
+    "Environment :: Web Environment",
+    "Intended Audience :: Developers",
+    "License :: OSI Approved :: Apache Software License",
+    "Natural Language :: English",
+    "Operating System :: OS Independent",
+    "Programming Language :: Python",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+    "Programming Language :: Python :: 3.12",
+    "Programming Language :: Python :: 3.13",
+    "Programming Language :: Python :: 3.14",
+    "Programming Language :: Python :: 3 :: Only",
+    "Programming Language :: Python :: Implementation :: CPython",
+    "Programming Language :: Python :: Implementation :: PyPy",
+    "Topic :: Internet :: WWW/HTTP",
+    "Topic :: Software Development :: Libraries"
+]
+
+[project.urls]
+Documentation = "https://requests.readthedocs.io"
+Source = "https://github.com/psf/requests"
+
+[project.optional-dependencies]
+security = []
+socks = ["PySocks>=1.5.6, !=1.5.7"]
+use_chardet_on_py3 = ["chardet>=3.0.2,<8"]
+test = [
+    "pytest-httpbin==2.1.0",
+    "pytest-cov",
+    "pytest-mock",
+    "pytest-xdist",
+    "PySocks>=1.5.6, !=1.5.7",
+    "pytest>=3"
+]
+
+[tool.setuptools]
+license-files = ["LICENSE", "NOTICE"]
+
+[tool.setuptools.dynamic]
+version = {attr = "requests.__version__.__version__"}
+
+[tool.setuptools.packages.find]
+where = ["src"]
+
+[tool.ruff]
+target-version = "py310"
+src = ["src/requests", "tests"]
+exclude = ["docs/", "ext/"]
+
+[tool.ruff.lint]
+select = [
+    "E",      # pycodestyle errors
+    "W",      # pycodestyle warnings
+    "F",      # pyflakes
+    "I",      # isort
+    "UP",     # pyupgrade
+    "T10",    # flake8-debugger (replaces debug-statements hook)
+]
+ignore = ["E203", "E501", "UP038", "UP031"]
+per-file-ignores = {"src/requests/__init__.py" = ["E402", "F401"], "src/requests/compat.py" = ["E402", "F401"], "tests/compat.py" = ["F401"]}
+
+[tool.ruff.lint.isort]
+known-first-party = ["requests"]
+
+[tool.ruff.format]
+# Use black-compatible formatting
+quote-style = "double"
+indent-style = "space"

[tool.pytest.ini_options]
addopts = "--doctest-modules"
diff --git setup.cfg setup.cfg
deleted file mode 100644
index 8d44e0e14b..0000000000
--- setup.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
-[metadata]
-license_file = LICENSE
-provides-extra =
-    socks
-    use_chardet_on_py3
-requires-dist =
-    certifi>=2017.4.17
-    charset_normalizer>=2,<4
-    idna>=2.5,<4
-    urllib3>=1.21.1,<3
-
-[flake8]
-ignore = E203, E501, W503
-per-file-ignores =
-    src/requests/__init__.py:E402, F401
-    src/requests/compat.py:E402, F401
-    tests/compat.py:F401
diff --git setup.py setup.py
index 7d9b52bc3b..1095518ac8 100755
--- setup.py
+++ setup.py
@@ -1,107 +1,9 @@
-#!/usr/bin/env python
-import os
import sys
-from codecs import open

-from setuptools import setup
-
-CURRENT_PYTHON = sys.version_info[:2]
-REQUIRED_PYTHON = (3, 8)
-
-if CURRENT_PYTHON < REQUIRED_PYTHON:
-    sys.stderr.write(
-        """
-==========================
-Unsupported Python version
-==========================
-This version of Requests requires at least Python {}.{}, but
-you're trying to install it on Python {}.{}. To resolve this,
-consider upgrading to a supported Python version.
-
-If you can't upgrade your Python version, you'll need to
-pin to an older version of Requests (<2.32.0).
-""".format(
-            *(REQUIRED_PYTHON + CURRENT_PYTHON)
-        )
-    )
+if sys.version_info < (3, 10):  # noqa: UP036
+    sys.stderr.write("Requests requires Python 3.10 or later.\n")
    sys.exit(1)

+from setuptools import setup

-# 'setup.py publish' shortcut.
-if sys.argv[-1] == "publish":
-    os.system("python setup.py sdist bdist_wheel")
-    os.system("twine upload dist/*")
-    sys.exit()
-
-requires = [
-    "charset_normalizer>=2,<4",
-    "idna>=2.5,<4",
-    "urllib3>=1.21.1,<3",
-    "certifi>=2017.4.17",
-]
-test_requirements = [
-    "pytest-httpbin==2.1.0",
-    "pytest-cov",
-    "pytest-mock",
-    "pytest-xdist",
-    "PySocks>=1.5.6, !=1.5.7",
-    "pytest>=3",
-]
-
-about = {}
-here = os.path.abspath(os.path.dirname(__file__))
-with open(os.path.join(here, "src", "requests", "__version__.py"), "r", "utf-8") as f:
-    exec(f.read(), about)
-
-with open("README.md", "r", "utf-8") as f:
-    readme = f.read()
-
-setup(
-    name=about["__title__"],
-    version=about["__version__"],
-    description=about["__description__"],
-    long_description=readme,
-    long_description_content_type="text/markdown",
-    author=about["__author__"],
-    author_email=about["__author_email__"],
-    url=about["__url__"],
-    packages=["requests"],
-    package_data={"": ["LICENSE", "NOTICE"]},
-    package_dir={"": "src"},
-    include_package_data=True,
-    python_requires=">=3.8",
-    install_requires=requires,
-    license=about["__license__"],
-    zip_safe=False,
-    classifiers=[
-        "Development Status :: 5 - Production/Stable",
-        "Environment :: Web Environment",
-        "Intended Audience :: Developers",
-        "License :: OSI Approved :: Apache Software License",
-        "Natural Language :: English",
-        "Operating System :: OS Independent",
-        "Programming Language :: Python",
-        "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.8",
-        "Programming Language :: Python :: 3.9",
-        "Programming Language :: Python :: 3.10",
-        "Programming Language :: Python :: 3.11",
-        "Programming Language :: Python :: 3.12",
-        "Programming Language :: Python :: 3.13",
-        "Programming Language :: Python :: 3 :: Only",
-        "Programming Language :: Python :: Implementation :: CPython",
-        "Programming Language :: Python :: Implementation :: PyPy",
-        "Topic :: Internet :: WWW/HTTP",
-        "Topic :: Software Development :: Libraries",
-    ],
-    tests_require=test_requirements,
-    extras_require={
-        "security": [],
-        "socks": ["PySocks>=1.5.6, !=1.5.7"],
-        "use_chardet_on_py3": ["chardet>=3.0.2,<6"],
-    },
-    project_urls={
-        "Documentation": "https://requests.readthedocs.io",
-        "Source": "https://github.com/psf/requests",
-    },
-)
+setup()
diff --git src/requests/__init__.py src/requests/__init__.py
index 051cda1340..8ecd8b8149 100644
--- src/requests/__init__.py
+++ src/requests/__init__.py
@@ -75,8 +75,8 @@ def check_compatibility(urllib3_version, chardet_version, charset_normalizer_ver
    if chardet_version:
        major, minor, patch = chardet_version.split(".")[:3]
        major, minor, patch = int(major), int(minor), int(patch)
-        # chardet_version >= 3.0.2, < 6.0.0
-        assert (3, 0, 2) <= (major, minor, patch) < (6, 0, 0)
+        # chardet_version >= 3.0.2, < 8.0.0
+        assert (3, 0, 2) <= (major, minor, patch) < (8, 0, 0)
    elif charset_normalizer_version:
        major, minor, patch = charset_normalizer_version.split(".")[:3]
        major, minor, patch = int(major), int(minor), int(patch)
@@ -98,8 +98,8 @@ def _check_cryptography(cryptography_version):
        return

    if cryptography_version < [1, 3, 4]:
-        warning = "Old version of cryptography ({}) may cause slowdown.".format(
-            cryptography_version
+        warning = (
+            f"Old version of cryptography ({cryptography_version}) may cause slowdown."
        )
        warnings.warn(warning, RequestsDependencyWarning)

@@ -111,10 +111,9 @@ def _check_cryptography(cryptography_version):
    )
except (AssertionError, ValueError):
    warnings.warn(
-        "urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported "
-        "version!".format(
-            urllib3.__version__, chardet_version, charset_normalizer_version
-        ),
+        f"urllib3 ({urllib3.__version__}) or chardet "
+        f"({chardet_version})/charset_normalizer ({charset_normalizer_version}) "
+        "doesn't match a supported version!",
        RequestsDependencyWarning,
    )

diff --git src/requests/__version__.py src/requests/__version__.py
index 3128a4644e..567b49f549 100644
--- src/requests/__version__.py
+++ src/requests/__version__.py
@@ -5,8 +5,8 @@
__title__ = "requests"
__description__ = "Python HTTP for Humans."
__url__ = "https://requests.readthedocs.io"
-__version__ = "2.32.4"
-__build__ = 0x023204
+__version__ = "2.33.0"
+__build__ = 0x023300
__author__ = "Kenneth Reitz"
__author_email__ = "me@kennethreitz.org"
__license__ = "Apache-2.0"
diff --git src/requests/_internal_utils.py src/requests/_internal_utils.py
index f2cf635e29..8c7c05190c 100644
--- src/requests/_internal_utils.py
+++ src/requests/_internal_utils.py
@@ -5,6 +5,7 @@
Provides utility functions that are consumed internally by Requests
which depend on extremely few external helpers (such as compat)
"""
+
import re

from .compat import builtin_str
diff --git src/requests/adapters.py src/requests/adapters.py
index 9a58b16025..98f74465f2 100644
--- src/requests/adapters.py
+++ src/requests/adapters.py
@@ -11,23 +11,24 @@
import typing
import warnings

-from urllib3.exceptions import ClosedPoolError, ConnectTimeoutError
-from urllib3.exceptions import HTTPError as _HTTPError
-from urllib3.exceptions import InvalidHeader as _InvalidHeader
from urllib3.exceptions import (
+    ClosedPoolError,
+    ConnectTimeoutError,
    LocationValueError,
    MaxRetryError,
    NewConnectionError,
    ProtocolError,
+    ReadTimeoutError,
+    ResponseError,
)
+from urllib3.exceptions import HTTPError as _HTTPError
+from urllib3.exceptions import InvalidHeader as _InvalidHeader
from urllib3.exceptions import ProxyError as _ProxyError
-from urllib3.exceptions import ReadTimeoutError, ResponseError
from urllib3.exceptions import SSLError as _SSLError
from urllib3.poolmanager import PoolManager, proxy_from_url
from urllib3.util import Timeout as TimeoutSauce
from urllib3.util import parse_url
from urllib3.util.retry import Retry
-from urllib3.util.ssl_ import create_urllib3_context

from .auth import _basic_auth_str
from .compat import basestring, urlparse
@@ -48,7 +49,6 @@
from .structures import CaseInsensitiveDict
from .utils import (
    DEFAULT_CA_BUNDLE_PATH,
-    extract_zipped_paths,
    get_auth_from_url,
    get_encoding_from_headers,
    prepend_scheme_if_needed,
@@ -74,44 +74,21 @@ def SOCKSProxyManager(*args, **kwargs):
DEFAULT_POOL_TIMEOUT = None


-try:
-    import ssl  # noqa: F401
-
-    _preloaded_ssl_context = create_urllib3_context()
-    _preloaded_ssl_context.load_verify_locations(
-        extract_zipped_paths(DEFAULT_CA_BUNDLE_PATH)
-    )
-except ImportError:
-    # Bypass default SSLContext creation when Python
-    # interpreter isn't built with the ssl module.
-    _preloaded_ssl_context = None
-
-
def _urllib3_request_context(
    request: "PreparedRequest",
    verify: "bool | str | None",
-    client_cert: "typing.Tuple[str, str] | str | None",
+    client_cert: "tuple[str, str] | str | None",
    poolmanager: "PoolManager",
-) -> "(typing.Dict[str, typing.Any], typing.Dict[str, typing.Any])":
+) -> "(dict[str, typing.Any], dict[str, typing.Any])":
    host_params = {}
    pool_kwargs = {}
    parsed_request_url = urlparse(request.url)
    scheme = parsed_request_url.scheme.lower()
    port = parsed_request_url.port

-    # Determine if we have and should use our default SSLContext
-    # to optimize performance on standard requests.
-    poolmanager_kwargs = getattr(poolmanager, "connection_pool_kw", {})
-    has_poolmanager_ssl_context = poolmanager_kwargs.get("ssl_context")
-    should_use_default_ssl_context = (
-        _preloaded_ssl_context is not None and not has_poolmanager_ssl_context
-    )
-
    cert_reqs = "CERT_REQUIRED"
    if verify is False:
        cert_reqs = "CERT_NONE"
-    elif verify is True and should_use_default_ssl_context:
-        pool_kwargs["ssl_context"] = _preloaded_ssl_context
    elif isinstance(verify, str):
        if not os.path.isdir(verify):
            pool_kwargs["ca_certs"] = verify
@@ -314,26 +291,27 @@ def cert_verify(self, conn, url, verify, cert):
        :param cert: The SSL certificate to verify.
        """
        if url.lower().startswith("https") and verify:
-            conn.cert_reqs = "CERT_REQUIRED"
+            cert_loc = None

-            # Only load the CA certificates if 'verify' is a string indicating the CA bundle to use.
-            # Otherwise, if verify is a boolean, we don't load anything since
-            # the connection will be using a context with the default certificates already loaded,
-            # and this avoids a call to the slow load_verify_locations()
+            # Allow self-specified cert location.
            if verify is not True:
-                # `verify` must be a str with a path then
                cert_loc = verify

-                if not os.path.exists(cert_loc):
-                    raise OSError(
-                        f"Could not find a suitable TLS CA certificate bundle, "
-                        f"invalid path: {cert_loc}"
-                    )
+            if not cert_loc:
+                cert_loc = DEFAULT_CA_BUNDLE_PATH
+
+            if not cert_loc or not os.path.exists(cert_loc):
+                raise OSError(
+                    f"Could not find a suitable TLS CA certificate bundle, "
+                    f"invalid path: {cert_loc}"
+                )
+
+            conn.cert_reqs = "CERT_REQUIRED"

-                if not os.path.isdir(cert_loc):
-                    conn.ca_certs = cert_loc
-                else:
-                    conn.ca_cert_dir = cert_loc
+            if not os.path.isdir(cert_loc):
+                conn.ca_certs = cert_loc
+            else:
+                conn.ca_cert_dir = cert_loc
        else:
            conn.cert_reqs = "CERT_NONE"
            conn.ca_certs = None
@@ -410,7 +388,7 @@ def build_connection_pool_key_attributes(self, request, verify, cert=None):
          ``"cert_reqs"`` will be set
        * If ``verify`` is a string, (i.e., it is a user-specified trust bundle)
          ``"ca_certs"`` will be set if the string is not a directory recognized
-          by :py:func:`os.path.isdir`, otherwise ``"ca_certs_dir"`` will be
+          by :py:func:`os.path.isdir`, otherwise ``"ca_cert_dir"`` will be
          set.
        * If ``"cert"`` is specified, ``"cert_file"`` will always be set. If
          ``"cert"`` is a tuple with a second item, ``"key_file"`` will also
diff --git src/requests/auth.py src/requests/auth.py
index 4a7ce6dc14..c39b645189 100644
--- src/requests/auth.py
+++ src/requests/auth.py
@@ -35,9 +35,9 @@ def _basic_auth_str(username, password):
    if not isinstance(username, basestring):
        warnings.warn(
            "Non-string usernames will no longer be supported in Requests "
-            "3.0.0. Please convert the object you've passed in ({!r}) to "
+            f"3.0.0. Please convert the object you've passed in ({username!r}) to "
            "a string or bytes object in the near future to avoid "
-            "problems.".format(username),
+            "problems.",
            category=DeprecationWarning,
        )
        username = str(username)
@@ -45,9 +45,9 @@ def _basic_auth_str(username, password):
    if not isinstance(password, basestring):
        warnings.warn(
            "Non-string passwords will no longer be supported in Requests "
-            "3.0.0. Please convert the object you've passed in ({!r}) to "
+            f"3.0.0. Please convert the object you've passed in ({type(password)!r}) to "
            "a string or bytes object in the near future to avoid "
-            "problems.".format(type(password)),
+            "problems.",
            category=DeprecationWarning,
        )
        password = str(password)
diff --git src/requests/certs.py src/requests/certs.py
index be422c3e91..4f85ac070b 100644
--- src/requests/certs.py
+++ src/requests/certs.py
@@ -11,6 +11,7 @@
environment, you can change the definition of where() to return a separately
packaged CA bundle.
"""
+
from certifi import where

if __name__ == "__main__":
diff --git src/requests/exceptions.py src/requests/exceptions.py
index 83986b4898..6e71506e96 100644
--- src/requests/exceptions.py
+++ src/requests/exceptions.py
@@ -4,6 +4,7 @@

This module contains the set of Requests' exceptions.
"""
+
from urllib3.exceptions import HTTPError as BaseHTTPError

from .compat import JSONDecodeError as CompatJSONDecodeError
diff --git src/requests/help.py src/requests/help.py
index 8fbcd6560a..5d5107895e 100644
--- src/requests/help.py
+++ src/requests/help.py
@@ -47,11 +47,8 @@ def _implementation():
    if implementation == "CPython":
        implementation_version = platform.python_version()
    elif implementation == "PyPy":
-        implementation_version = "{}.{}.{}".format(
-            sys.pypy_version_info.major,
-            sys.pypy_version_info.minor,
-            sys.pypy_version_info.micro,
-        )
+        pypy = sys.pypy_version_info
+        implementation_version = f"{pypy.major}.{pypy.minor}.{pypy.micro}"
        if sys.pypy_version_info.releaselevel != "final":
            implementation_version = "".join(
                [implementation_version, sys.pypy_version_info.releaselevel]
diff --git src/requests/hooks.py src/requests/hooks.py
index d181ba2ec2..5976bc7d0f 100644
--- src/requests/hooks.py
+++ src/requests/hooks.py
@@ -9,6 +9,7 @@
``response``:
    The response generated from a Request.
"""
+
HOOKS = ["response"]


diff --git src/requests/models.py src/requests/models.py
index c4b25fa079..2d043f59cf 100644
--- src/requests/models.py
+++ src/requests/models.py
@@ -34,9 +34,11 @@
    builtin_str,
    chardet,
    cookielib,
+    urlencode,
+    urlsplit,
+    urlunparse,
)
from .compat import json as complexjson
-from .compat import urlencode, urlsplit, urlunparse
from .cookies import _copy_cookie_jar, cookiejar_from_dict, get_cookie_header
from .exceptions import (
    ChunkedEncodingError,
@@ -45,11 +47,11 @@
    HTTPError,
    InvalidJSONError,
    InvalidURL,
+    MissingSchema,
+    StreamConsumedError,
)
from .exceptions import JSONDecodeError as RequestsJSONDecodeError
-from .exceptions import MissingSchema
from .exceptions import SSLError as RequestsSSLError
-from .exceptions import StreamConsumedError
from .hooks import default_hooks
from .status_codes import codes
from .structures import CaseInsensitiveDict
diff --git src/requests/sessions.py src/requests/sessions.py
index b387bc36df..578cc44d5c 100644
--- src/requests/sessions.py
+++ src/requests/sessions.py
@@ -5,6 +5,7 @@
This module provides a Session object to manage and persist settings across
requests (cookies, auth, proxies).
"""
+
import os
import sys
import time
@@ -421,6 +422,8 @@ def __init__(self):
        #: expired certificates, which will make your application vulnerable to
        #: man-in-the-middle (MitM) attacks.
        #: Only set this to `False` for testing.
+        #: If verify is set to a string, it must be the path to a CA bundle file
+        #: that will be used to verify the TLS certificate.
        self.verify = True

        #: SSL client certificate default, if String, path to ssl client
@@ -535,7 +538,7 @@ def request(
            for multipart encoding upload.
        :param auth: (optional) Auth tuple or callable to enable
            Basic/Digest/Custom HTTP Auth.
-        :param timeout: (optional) How long to wait for the server to send
+        :param timeout: (optional) How many seconds to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple
diff --git src/requests/utils.py src/requests/utils.py
index 8ab55852cc..54959bb8ab 100644
--- src/requests/utils.py
+++ src/requests/utils.py
@@ -39,9 +39,6 @@
    getproxies_environment,
    integer_types,
    is_urllib3_1,
-)
-from .compat import parse_http_list as _parse_list_header
-from .compat import (
    proxy_bypass,
    proxy_bypass_environment,
    quote,
@@ -50,6 +47,7 @@
    urlparse,
    urlunparse,
)
+from .compat import parse_http_list as _parse_list_header
from .cookies import cookiejar_from_dict
from .exceptions import (
    FileModeWarning,
@@ -61,6 +59,7 @@

NETRC_FILES = (".netrc", "_netrc")

+# Certificate is extracted by certifi when needed.
DEFAULT_CA_BUNDLE_PATH = certs.where()

DEFAULT_PORTS = {"http": 80, "https": 443}
@@ -233,7 +232,7 @@ def get_netrc_auth(url, raise_errors=False):

        try:
            _netrc = netrc(netrc_path).authenticators(host)
-            if _netrc:
+            if _netrc and any(_netrc):
                # Return with login / password
                login_i = 0 if _netrc[0] else 1
                return (_netrc[login_i], _netrc[2])
@@ -283,12 +282,13 @@ def extract_zipped_paths(path):
        return path

    # we have a valid zip archive and a valid member of that archive
-    tmp = tempfile.gettempdir()
-    extracted_path = os.path.join(tmp, member.split("/")[-1])
-    if not os.path.exists(extracted_path):
-        # use read + write to avoid the creating nested folders, we only want the file, avoids mkdir racing condition
-        with atomic_open(extracted_path) as file_handler:
-            file_handler.write(zip_file.read(member))
+    suffix = os.path.splitext(member.split("/")[-1])[-1]
+    fd, extracted_path = tempfile.mkstemp(suffix=suffix)
+    try:
+        os.write(fd, zip_file.read(member))
+    finally:
+        os.close(fd)
+
    return extracted_path


diff --git tests/test_lowlevel.py tests/test_lowlevel.py
index 859d07e8a5..0a722b07a5 100644
--- tests/test_lowlevel.py
+++ tests/test_lowlevel.py
@@ -1,10 +1,10 @@
import threading

import pytest
-from tests.testserver.server import Server, consume_socket_content

import requests
from requests.compat import JSONDecodeError
+from tests.testserver.server import Server, consume_socket_content

from .utils import override_environ

diff --git tests/test_requests.py tests/test_requests.py
index 75d2deff2e..257d9d7ab1 100644
--- tests/test_requests.py
+++ tests/test_requests.py
@@ -44,9 +44,11 @@
    ReadTimeout,
    RequestException,
    RetryError,
+    Timeout,
+    TooManyRedirects,
+    UnrewindableBodyError,
)
from requests.exceptions import SSLError as RequestsSSLError
-from requests.exceptions import Timeout, TooManyRedirects, UnrewindableBodyError
from requests.hooks import default_hooks
from requests.models import PreparedRequest, urlencode
from requests.sessions import SessionRedirectMixin
@@ -960,20 +962,18 @@ def test_invalid_ca_certificate_path(self, httpbin_secure):
        INVALID_PATH = "/garbage"
        with pytest.raises(IOError) as e:
            requests.get(httpbin_secure(), verify=INVALID_PATH)
-        assert str(
-            e.value
-        ) == "Could not find a suitable TLS CA certificate bundle, invalid path: {}".format(
-            INVALID_PATH
+        assert (
+            str(e.value)
+            == f"Could not find a suitable TLS CA certificate bundle, invalid path: {INVALID_PATH}"
        )

    def test_invalid_ssl_certificate_files(self, httpbin_secure):
        INVALID_PATH = "/garbage"
        with pytest.raises(IOError) as e:
            requests.get(httpbin_secure(), cert=INVALID_PATH)
-        assert str(
-            e.value
-        ) == "Could not find the TLS certificate file, invalid path: {}".format(
-            INVALID_PATH
+        assert (
+            str(e.value)
+            == f"Could not find the TLS certificate file, invalid path: {INVALID_PATH}"
        )

        with pytest.raises(IOError) as e:
@@ -2460,7 +2460,6 @@ def test_expires_none(self):


class TestMorselToCookieMaxAge:
-
    """Tests for morsel_to_cookie when morsel contains max-age."""

    def test_max_age_valid_int(self):
diff --git tests/test_testserver.py tests/test_testserver.py
index c73a3f1f59..b343482b2c 100644
--- tests/test_testserver.py
+++ tests/test_testserver.py
@@ -3,9 +3,9 @@
import time

import pytest
-from tests.testserver.server import Server

import requests
+from tests.testserver.server import Server


class TestTestServer:
@@ -42,7 +42,7 @@ def test_server_closes(self):
    def test_text_response(self):
        """the text_response_server sends the given text"""
        server = Server.text_response_server(
-            "HTTP/1.1 200 OK\r\n" "Content-Length: 6\r\n" "\r\nroflol"
+            "HTTP/1.1 200 OK\r\nContent-Length: 6\r\n\r\nroflol"
        )

        with server as (host, port):
diff --git tests/test_utils.py tests/test_utils.py
index f9a287af1b..c477c4089a 100644
--- tests/test_utils.py
+++ tests/test_utils.py
@@ -170,6 +170,16 @@ def test_not_vulnerable_to_bad_url_parsing(self, tmp_path, monkeypatch):
        auth = get_netrc_auth("http://example.com:@evil.com/&apos;")
        assert auth is None

+    def test_empty_default_credentials_ignored(self, tmp_path, monkeypatch):
+        """Empty default credentials should not be returned."""
+        netrc_path = tmp_path / ".netrc"
+        monkeypatch.setenv("NETRC", str(netrc_path))
+        with open(netrc_path, "w") as f:
+            f.write("machine example.com login user password pass\ndefault\n")
+
+        auth = get_netrc_auth("http://httpbin.org/")
+        assert auth is None
+

class TestToKeyValList:
    @pytest.mark.parametrize(
diff --git tox.ini tox.ini
index 79f74b2567..b316359aae 100644
--- tox.ini
+++ tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py{38,39,310,311,312,313}-{default, use_chardet_on_py3}
+envlist = py{310,311,312,313,314}-{default, use_chardet_on_py3}

[testenv]
deps = -rrequirements-dev.txt

Description

This pull request primarily updates the project's GitHub Actions workflows, replaces certain dependencies and improves overall maintenance. The main changes include:

  1. Add .github/CODEOWNERS to restrict editing of key deployment files to specific maintainers.
  2. Update GitHub Actions Workflows:
    • Update references to actions with newer versions in codeql-analysis.yml, lint.yml, lock-issues.yml, and run-tests.yml.
    • Add publish.yml to automate publishing to PyPI on tag pushes and workflow dispatch triggers.
  3. Modify pre-commit hooks:
    • Replace multiple linting/pre-commit tools with ruff.
  4. Documentation Updates:
    • Revise and reorganize AUTHORS.rst and HISTORY.md.
    • Update README.md with new badges and support version changes.
  5. Update Build and Test Configurations:
    • Switch to PEP 517 build system in pyproject.toml.
    • Remove setup.py content and adapt portions to pyproject.toml.
    • Remove support for older Python versions and add compatibility with newer ones.
  6. Refactor Code:
    • Internal reorganization and modernization in source files, enhance readability and maintainability.

Possible Issues

  1. Backward Compatibility: Dropping support for older Python versions (e.g., Python 3.9 and below) might affect users who haven't upgraded yet.
  2. Removed Testing and Linting Tools: Replacing tools like isort, black, pyupgrade, flake8 with ruff could introduce new issues if ruff does not fully cover the previous tools' rules.
  3. Publish to PyPI Workflow: Publishing automation needs thorough testing to ensure it doesn't publish unintended versions.

Security Hotspots

  1. Automated Publish Workflow (.github/workflows/publish.yml):

    • Ensure the credentials used for uploading dists to PyPI are secured and not exposed.
    • Validate tag pushes to ensure only intended versions are published.
  2. Dependency Updates:

    • Ensure no vulnerabilities are introduced with the new versions of actions and packages used.

Privacy Hotspots

None identified.

Changes

Changes

  1. New File: .github/CODEOWNERS
    +# Restrict all files related to deploying to
    +# require lead maintainer approval.
    +
    +.github/workflows/            @nateprewitt @sigmavirus24
    +.github/CODEOWNERS            @nateprewitt @sigmavirus24
    +src/requests/__version__.py   @nateprewitt @sigmavirus24
    +HISTORY.md                    @nateprewitt @sigmavirus24
    +pyproject.toml                @nateprewitt @sigmavirus24
    
  2. Updated Workflows:
    • .github/workflows/codeql-analysis.yml
    • .github/workflows/lint.yml
    • .github/workflows/lock-issues.yml
    • .github/workflows/run-tests.yml
  3. New Workflow: .github/workflows/publish.yml
    +name: Publish to PyPI
    +# Workflow content
    
  4. Refactor Pre-commit Config: .pre-commit-config.yaml
    • Removed several individual hooks and added ruff.
    -- repo: https://github.com/PyCQA/isort
    -- repo: https://github.com/psf/black
    -- repo: https://github.com/asottile/pyupgrade
    -- repo: https://github.com/PyCQA/flake8
    +- repo: https://github.com/astral-sh/ruff-pre-commit
    
  5. Documentation Updates:
    • AUTHORS.rst
    • HISTORY.md
    • README.md
  6. Build System:
    • .pre-commit-config.yaml
    • pyproject.toml
    • setup.cfg (deleted)
    • setup.py
  7. Code Refactoring:
    • Various files in src/requests/
sequenceDiagram
    participant Dev as Developer
    participant CodeBase as CodeBase
    participant Actions as GitHub Actions

    Dev->>CodeBase: Update .github/CODEOWNERS
    Dev->>CodeBase: Update GitHub Actions Workflows
    Dev->>CodeBase: Add publish.yml workflow
    Dev->>CodeBase: Replace pre-commit hooks with ruff
    Dev->>CodeBase: Update documentation
    Dev->>CodeBase: Update build configurations
    Dev->>CodeBase: Refactor code

    CodeBase->>Actions: Trigger Actions for new config and tests
    Actions->>CodeBase: Execute and report results
Loading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file p2 puLL-Merge python Pull requests that update python code security

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants