We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Create a workflow (nox?) for testing Emscripten support locally
Would be great to have an easy-to-use workflow for contributors to:

* Run a single command
* Have all dependencies installed
* Opens a Pyodide console in a web browser
* Makes the local copy of urllib3 available for installation with micropip/Pyodide

This would help greatly with being able to poke around with and develop Emscripten/Pyodide support.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `noxfile.py`
Content:
```
1 from __future__ import annotations
2 
3 import os
4 import shutil
5 import sys
6 import typing
7 from pathlib import Path
8 
9 import nox
10 
11 nox.options.error_on_missing_interpreters = True
12 
13 
14 def tests_impl(
15     session: nox.Session,
16     extras: str = "socks,brotli,zstd,h2",
17     # hypercorn dependency h2 compares bytes and strings
18     # https://github.com/python-hyper/h2/issues/1236
19     byte_string_comparisons: bool = False,
20     integration: bool = False,
21     pytest_extra_args: list[str] = [],
22 ) -> None:
23     # Retrieve sys info from the Python implementation under test
24     # to avoid enabling memray when nox runs under CPython but tests PyPy
25     session_python_info = session.run(
26         "python",
27         "-c",
28         "import sys; print(sys.implementation.name, sys.version_info.releaselevel)",
29         silent=True,
30     ).strip()  # type: ignore[union-attr] # mypy doesn't know that silent=True  will return a string
31     implementation_name, release_level = session_python_info.split(" ")
32 
33     # zstd cannot be installed on CPython 3.13 yet because it pins
34     # an incompatible CFFI version.
35     # https://github.com/indygreg/python-zstandard/issues/210
36     if release_level != "final":
37         extras = extras.replace(",zstd", "")
38 
39     # Install deps and the package itself.
40     session.install("-r", "dev-requirements.txt")
41     session.install(f".[{extras}]")
42 
43     # Show the pip version.
44     session.run("pip", "--version")
45     # Print the Python version and bytesize.
46     session.run("python", "--version")
47     session.run("python", "-c", "import struct; print(struct.calcsize('P') * 8)")
48     # Print OpenSSL information.
49     session.run("python", "-m", "OpenSSL.debug")
50 
51     memray_supported = True
52     if implementation_name != "cpython" or release_level != "final":
53         memray_supported = False  # pytest-memray requires CPython 3.8+
54     elif sys.platform == "win32":
55         memray_supported = False
56 
57     # Environment variables being passed to the pytest run.
58     pytest_session_envvars = {
59         "PYTHONWARNINGS": "always::DeprecationWarning",
60     }
61 
62     # In coverage 7.4.0 we can only set the setting for Python 3.12+
63     # Future versions of coverage will use sys.monitoring based on availability.
64     if (
65         isinstance(session.python, str)
66         and "." in session.python
67         and int(session.python.split(".")[1]) >= 12
68     ):
69         pytest_session_envvars["COVERAGE_CORE"] = "sysmon"
70 
71     # Inspired from https://hynek.me/articles/ditch-codecov-python/
72     # We use parallel mode and then combine in a later CI step
73     session.run(
74         "python",
75         *(("-bb",) if byte_string_comparisons else ()),
76         "-m",
77         "coverage",
78         "run",
79         "--parallel-mode",
80         "-m",
81         "pytest",
82         *("--memray", "--hide-memray-summary") if memray_supported else (),
83         "-v",
84         "-ra",
85         *(("--integration",) if integration else ()),
86         f"--color={'yes' if 'GITHUB_ACTIONS' in os.environ else 'auto'}",
87         "--tb=native",
88         "--durations=10",
89         "--strict-config",
90         "--strict-markers",
91         *pytest_extra_args,
92         *(session.posargs or ("test/",)),
93         env=pytest_session_envvars,
94     )
95 
96 
97 @nox.session(
98     python=[
99         "3.8",
100         "3.9",
101         "3.10",
102         "3.11",
103         "3.12",
104         "3.13",
105         "pypy3.8",
106         "pypy3.9",
107         "pypy3.10",
108     ]
109 )
110 def test(session: nox.Session) -> None:
111     tests_impl(session)
112 
113 
114 @nox.session(python="3")
115 def test_integration(session: nox.Session) -> None:
116     """Run integration tests"""
117     tests_impl(session, integration=True)
118 
119 
120 @nox.session(python="3")
121 def test_brotlipy(session: nox.Session) -> None:
122     """Check that if 'brotlipy' is installed instead of 'brotli' or
123     'brotlicffi' that we still don't blow up.
124     """
125     session.install("brotlipy")
126     tests_impl(session, extras="socks", byte_string_comparisons=False)
127 
128 
129 def git_clone(session: nox.Session, git_url: str) -> None:
130     """We either clone the target repository or if already exist
131     simply reset the state and pull.
132     """
133     expected_directory = git_url.split("/")[-1]
134 
135     if expected_directory.endswith(".git"):
136         expected_directory = expected_directory[:-4]
137 
138     if not os.path.isdir(expected_directory):
139         session.run("git", "clone", "--depth", "1", git_url, external=True)
140     else:
141         session.run(
142             "git", "-C", expected_directory, "reset", "--hard", "HEAD", external=True
143         )
144         session.run("git", "-C", expected_directory, "pull", external=True)
145 
146 
147 @nox.session()
148 def downstream_botocore(session: nox.Session) -> None:
149     root = os.getcwd()
150     tmp_dir = session.create_tmp()
151 
152     session.cd(tmp_dir)
153     git_clone(session, "https://github.com/boto/botocore")
154     session.chdir("botocore")
155     session.run("git", "rev-parse", "HEAD", external=True)
156     session.run("python", "scripts/ci/install")
157 
158     session.cd(root)
159     session.install(".", silent=False)
160     session.cd(f"{tmp_dir}/botocore")
161 
162     session.run("python", "-c", "import urllib3; print(urllib3.__version__)")
163     session.run("python", "scripts/ci/run-tests")
164 
165 
166 @nox.session()
167 def downstream_requests(session: nox.Session) -> None:
168     root = os.getcwd()
169     tmp_dir = session.create_tmp()
170 
171     session.cd(tmp_dir)
172     git_clone(session, "https://github.com/psf/requests")
173     session.chdir("requests")
174     session.run("git", "rev-parse", "HEAD", external=True)
175     session.install(".[socks]", silent=False)
176     session.install("-r", "requirements-dev.txt", silent=False)
177 
178     # Workaround until https://github.com/psf/httpbin/pull/29 gets released
179     session.install("flask<3", "werkzeug<3", silent=False)
180 
181     session.cd(root)
182     session.install(".", silent=False)
183     session.cd(f"{tmp_dir}/requests")
184 
185     session.run("python", "-c", "import urllib3; print(urllib3.__version__)")
186     session.run("pytest", "tests")
187 
188 
189 @nox.session()
190 def format(session: nox.Session) -> None:
191     """Run code formatters."""
192     lint(session)
193 
194 
195 @nox.session(python="3.12")
196 def lint(session: nox.Session) -> None:
197     session.install("pre-commit")
198     session.run("pre-commit", "run", "--all-files")
199 
200     mypy(session)
201 
202 
203 # TODO: node support is not tested yet - it should work if you require('xmlhttprequest') before
204 # loading pyodide, but there is currently no nice way to do this with pytest-pyodide
205 # because you can't override the test runner properties easily - see
206 # https://github.com/pyodide/pytest-pyodide/issues/118 for more
207 @nox.session(python="3.11")
208 @nox.parametrize("runner", ["firefox", "chrome"])
209 def emscripten(session: nox.Session, runner: str) -> None:
210     """Test on Emscripten with Pyodide & Chrome / Firefox"""
211     session.install("-r", "emscripten-requirements.txt")
212     # build wheel into dist folder
213     session.run("python", "-m", "build")
214     # make sure we have a dist dir for pyodide
215     dist_dir = None
216     if "PYODIDE_ROOT" in os.environ:
217         # we have a pyodide build tree checked out
218         # use the dist directory from that
219         dist_dir = Path(os.environ["PYODIDE_ROOT"]) / "dist"
220     else:
221         # we don't have a build tree, get one
222         # that matches the version of pyodide build
223         pyodide_version = typing.cast(
224             str,
225             session.run(
226                 "python",
227                 "-c",
228                 "import pyodide_build;print(pyodide_build.__version__)",
229                 silent=True,
230             ),
231         ).strip()
232 
233         pyodide_artifacts_path = Path(session.cache_dir) / f"pyodide-{pyodide_version}"
234         if not pyodide_artifacts_path.exists():
235             print("Fetching pyodide build artifacts")
236             session.run(
237                 "wget",
238                 f"https://github.com/pyodide/pyodide/releases/download/{pyodide_version}/pyodide-{pyodide_version}.tar.bz2",
239                 "-O",
240                 f"{pyodide_artifacts_path}.tar.bz2",
241             )
242             pyodide_artifacts_path.mkdir(parents=True)
243             session.run(
244                 "tar",
245                 "-xjf",
246                 f"{pyodide_artifacts_path}.tar.bz2",
247                 "-C",
248                 str(pyodide_artifacts_path),
249                 "--strip-components",
250                 "1",
251             )
252 
253         dist_dir = pyodide_artifacts_path
254     assert dist_dir is not None
255     assert dist_dir.exists()
256     if runner == "chrome":
257         # install chrome webdriver and add it to path
258         driver = typing.cast(
259             str,
260             session.run(
261                 "python",
262                 "-c",
263                 "from webdriver_manager.chrome import ChromeDriverManager;print(ChromeDriverManager().install())",
264                 silent=True,
265             ),
266         ).strip()
267         session.env["PATH"] = f"{Path(driver).parent}:{session.env['PATH']}"
268 
269         tests_impl(
270             session,
271             pytest_extra_args=[
272                 "--rt",
273                 "chrome-no-host",
274                 "--dist-dir",
275                 str(dist_dir),
276                 "test",
277             ],
278         )
279     elif runner == "firefox":
280         driver = typing.cast(
281             str,
282             session.run(
283                 "python",
284                 "-c",
285                 "from webdriver_manager.firefox import GeckoDriverManager;print(GeckoDriverManager().install())",
286                 silent=True,
287             ),
288         ).strip()
289         session.env["PATH"] = f"{Path(driver).parent}:{session.env['PATH']}"
290 
291         tests_impl(
292             session,
293             pytest_extra_args=[
294                 "--rt",
295                 "firefox-no-host",
296                 "--dist-dir",
297                 str(dist_dir),
298                 "test",
299             ],
300         )
301     else:
302         raise ValueError(f"Unknown runner: {runner}")
303 
304 
305 @nox.session(python="3.12")
306 def mypy(session: nox.Session) -> None:
307     """Run mypy."""
308     session.install("-r", "mypy-requirements.txt")
309     session.run("mypy", "--version")
310     session.run(
311         "mypy",
312         "-p",
313         "dummyserver",
314         "-m",
315         "noxfile",
316         "-p",
317         "urllib3",
318         "-p",
319         "test",
320     )
321 
322 
323 @nox.session
324 def docs(session: nox.Session) -> None:
325     session.install("-r", "docs/requirements.txt")
326     session.install(".[socks,brotli,zstd]")
327 
328     session.chdir("docs")
329     if os.path.exists("_build"):
330         shutil.rmtree("_build")
331     session.run("sphinx-build", "-b", "html", "-W", ".", "_build/html")
332
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/noxfile.py b/noxfile.py
--- a/noxfile.py
+++ b/noxfile.py
@@ -200,6 +200,21 @@
     mypy(session)
 
 
+@nox.session(python="3.11")
+def pyodideconsole(session: nox.Session) -> None:
+    # build wheel into dist folder
+    session.install("build")
+    session.run("python", "-m", "build")
+    session.run(
+        "cp",
+        "test/contrib/emscripten/templates/pyodide-console.html",
+        "dist/index.html",
+        external=True,
+    )
+    session.cd("dist")
+    session.run("python", "-m", "http.server")
+
+
 # TODO: node support is not tested yet - it should work if you require('xmlhttprequest') before
 # loading pyodide, but there is currently no nice way to do this with pytest-pyodide
 # because you can't override the test runner properties easily - see

{"golden_diff": "diff --git a/noxfile.py b/noxfile.py\n--- a/noxfile.py\n+++ b/noxfile.py\n@@ -200,6 +200,21 @@\n     mypy(session)\n \n \n+@nox.session(python=\"3.11\")\n+def pyodideconsole(session: nox.Session) -> None:\n+    # build wheel into dist folder\n+    session.install(\"build\")\n+    session.run(\"python\", \"-m\", \"build\")\n+    session.run(\n+        \"cp\",\n+        \"test/contrib/emscripten/templates/pyodide-console.html\",\n+        \"dist/index.html\",\n+        external=True,\n+    )\n+    session.cd(\"dist\")\n+    session.run(\"python\", \"-m\", \"http.server\")\n+\n+\n # TODO: node support is not tested yet - it should work if you require('xmlhttprequest') before\n # loading pyodide, but there is currently no nice way to do this with pytest-pyodide\n # because you can't override the test runner properties easily - see\n", "issue": "Create a workflow (nox?) for testing Emscripten support locally\nWould be great to have an easy-to-use workflow for contributors to:\r\n\r\n* Run a single command\r\n* Have all dependencies installed\r\n* Opens a Pyodide console in a web browser\r\n* Makes the local copy of urllib3 available for installation with micropip/Pyodide\r\n\r\nThis would help greatly with being able to poke around with and develop Emscripten/Pyodide support.\n", "before_files": [{"content": "from __future__ import annotations\n\nimport os\nimport shutil\nimport sys\nimport typing\nfrom pathlib import Path\n\nimport nox\n\nnox.options.error_on_missing_interpreters = True\n\n\ndef tests_impl(\n    session: nox.Session,\n    extras: str = \"socks,brotli,zstd,h2\",\n    # hypercorn dependency h2 compares bytes and strings\n    # https://github.com/python-hyper/h2/issues/1236\n    byte_string_comparisons: bool = False,\n    integration: bool = False,\n    pytest_extra_args: list[str] = [],\n) -> None:\n    # Retrieve sys info from the Python implementation under test\n    # to avoid enabling memray when nox runs under CPython but tests PyPy\n    session_python_info = session.run(\n        \"python\",\n        \"-c\",\n        \"import sys; print(sys.implementation.name, sys.version_info.releaselevel)\",\n        silent=True,\n    ).strip()  # type: ignore[union-attr] # mypy doesn't know that silent=True  will return a string\n    implementation_name, release_level = session_python_info.split(\" \")\n\n    # zstd cannot be installed on CPython 3.13 yet because it pins\n    # an incompatible CFFI version.\n    # https://github.com/indygreg/python-zstandard/issues/210\n    if release_level != \"final\":\n        extras = extras.replace(\",zstd\", \"\")\n\n    # Install deps and the package itself.\n    session.install(\"-r\", \"dev-requirements.txt\")\n    session.install(f\".[{extras}]\")\n\n    # Show the pip version.\n    session.run(\"pip\", \"--version\")\n    # Print the Python version and bytesize.\n    session.run(\"python\", \"--version\")\n    session.run(\"python\", \"-c\", \"import struct; print(struct.calcsize('P') * 8)\")\n    # Print OpenSSL information.\n    session.run(\"python\", \"-m\", \"OpenSSL.debug\")\n\n    memray_supported = True\n    if implementation_name != \"cpython\" or release_level != \"final\":\n        memray_supported = False  # pytest-memray requires CPython 3.8+\n    elif sys.platform == \"win32\":\n        memray_supported = False\n\n    # Environment variables being passed to the pytest run.\n    pytest_session_envvars = {\n        \"PYTHONWARNINGS\": \"always::DeprecationWarning\",\n    }\n\n    # In coverage 7.4.0 we can only set the setting for Python 3.12+\n    # Future versions of coverage will use sys.monitoring based on availability.\n    if (\n        isinstance(session.python, str)\n        and \".\" in session.python\n        and int(session.python.split(\".\")[1]) >= 12\n    ):\n        pytest_session_envvars[\"COVERAGE_CORE\"] = \"sysmon\"\n\n    # Inspired from https://hynek.me/articles/ditch-codecov-python/\n    # We use parallel mode and then combine in a later CI step\n    session.run(\n        \"python\",\n        *((\"-bb\",) if byte_string_comparisons else ()),\n        \"-m\",\n        \"coverage\",\n        \"run\",\n        \"--parallel-mode\",\n        \"-m\",\n        \"pytest\",\n        *(\"--memray\", \"--hide-memray-summary\") if memray_supported else (),\n        \"-v\",\n        \"-ra\",\n        *((\"--integration\",) if integration else ()),\n        f\"--color={'yes' if 'GITHUB_ACTIONS' in os.environ else 'auto'}\",\n        \"--tb=native\",\n        \"--durations=10\",\n        \"--strict-config\",\n        \"--strict-markers\",\n        *pytest_extra_args,\n        *(session.posargs or (\"test/\",)),\n        env=pytest_session_envvars,\n    )\n\n\n@nox.session(\n    python=[\n        \"3.8\",\n        \"3.9\",\n        \"3.10\",\n        \"3.11\",\n        \"3.12\",\n        \"3.13\",\n        \"pypy3.8\",\n        \"pypy3.9\",\n        \"pypy3.10\",\n    ]\n)\ndef test(session: nox.Session) -> None:\n    tests_impl(session)\n\n\n@nox.session(python=\"3\")\ndef test_integration(session: nox.Session) -> None:\n    \"\"\"Run integration tests\"\"\"\n    tests_impl(session, integration=True)\n\n\n@nox.session(python=\"3\")\ndef test_brotlipy(session: nox.Session) -> None:\n    \"\"\"Check that if 'brotlipy' is installed instead of 'brotli' or\n    'brotlicffi' that we still don't blow up.\n    \"\"\"\n    session.install(\"brotlipy\")\n    tests_impl(session, extras=\"socks\", byte_string_comparisons=False)\n\n\ndef git_clone(session: nox.Session, git_url: str) -> None:\n    \"\"\"We either clone the target repository or if already exist\n    simply reset the state and pull.\n    \"\"\"\n    expected_directory = git_url.split(\"/\")[-1]\n\n    if expected_directory.endswith(\".git\"):\n        expected_directory = expected_directory[:-4]\n\n    if not os.path.isdir(expected_directory):\n        session.run(\"git\", \"clone\", \"--depth\", \"1\", git_url, external=True)\n    else:\n        session.run(\n            \"git\", \"-C\", expected_directory, \"reset\", \"--hard\", \"HEAD\", external=True\n        )\n        session.run(\"git\", \"-C\", expected_directory, \"pull\", external=True)\n\n\n@nox.session()\ndef downstream_botocore(session: nox.Session) -> None:\n    root = os.getcwd()\n    tmp_dir = session.create_tmp()\n\n    session.cd(tmp_dir)\n    git_clone(session, \"https://github.com/boto/botocore\")\n    session.chdir(\"botocore\")\n    session.run(\"git\", \"rev-parse\", \"HEAD\", external=True)\n    session.run(\"python\", \"scripts/ci/install\")\n\n    session.cd(root)\n    session.install(\".\", silent=False)\n    session.cd(f\"{tmp_dir}/botocore\")\n\n    session.run(\"python\", \"-c\", \"import urllib3; print(urllib3.__version__)\")\n    session.run(\"python\", \"scripts/ci/run-tests\")\n\n\n@nox.session()\ndef downstream_requests(session: nox.Session) -> None:\n    root = os.getcwd()\n    tmp_dir = session.create_tmp()\n\n    session.cd(tmp_dir)\n    git_clone(session, \"https://github.com/psf/requests\")\n    session.chdir(\"requests\")\n    session.run(\"git\", \"rev-parse\", \"HEAD\", external=True)\n    session.install(\".[socks]\", silent=False)\n    session.install(\"-r\", \"requirements-dev.txt\", silent=False)\n\n    # Workaround until https://github.com/psf/httpbin/pull/29 gets released\n    session.install(\"flask<3\", \"werkzeug<3\", silent=False)\n\n    session.cd(root)\n    session.install(\".\", silent=False)\n    session.cd(f\"{tmp_dir}/requests\")\n\n    session.run(\"python\", \"-c\", \"import urllib3; print(urllib3.__version__)\")\n    session.run(\"pytest\", \"tests\")\n\n\n@nox.session()\ndef format(session: nox.Session) -> None:\n    \"\"\"Run code formatters.\"\"\"\n    lint(session)\n\n\n@nox.session(python=\"3.12\")\ndef lint(session: nox.Session) -> None:\n    session.install(\"pre-commit\")\n    session.run(\"pre-commit\", \"run\", \"--all-files\")\n\n    mypy(session)\n\n\n# TODO: node support is not tested yet - it should work if you require('xmlhttprequest') before\n# loading pyodide, but there is currently no nice way to do this with pytest-pyodide\n# because you can't override the test runner properties easily - see\n# https://github.com/pyodide/pytest-pyodide/issues/118 for more\n@nox.session(python=\"3.11\")\n@nox.parametrize(\"runner\", [\"firefox\", \"chrome\"])\ndef emscripten(session: nox.Session, runner: str) -> None:\n    \"\"\"Test on Emscripten with Pyodide & Chrome / Firefox\"\"\"\n    session.install(\"-r\", \"emscripten-requirements.txt\")\n    # build wheel into dist folder\n    session.run(\"python\", \"-m\", \"build\")\n    # make sure we have a dist dir for pyodide\n    dist_dir = None\n    if \"PYODIDE_ROOT\" in os.environ:\n        # we have a pyodide build tree checked out\n        # use the dist directory from that\n        dist_dir = Path(os.environ[\"PYODIDE_ROOT\"]) / \"dist\"\n    else:\n        # we don't have a build tree, get one\n        # that matches the version of pyodide build\n        pyodide_version = typing.cast(\n            str,\n            session.run(\n                \"python\",\n                \"-c\",\n                \"import pyodide_build;print(pyodide_build.__version__)\",\n                silent=True,\n            ),\n        ).strip()\n\n        pyodide_artifacts_path = Path(session.cache_dir) / f\"pyodide-{pyodide_version}\"\n        if not pyodide_artifacts_path.exists():\n            print(\"Fetching pyodide build artifacts\")\n            session.run(\n                \"wget\",\n                f\"https://github.com/pyodide/pyodide/releases/download/{pyodide_version}/pyodide-{pyodide_version}.tar.bz2\",\n                \"-O\",\n                f\"{pyodide_artifacts_path}.tar.bz2\",\n            )\n            pyodide_artifacts_path.mkdir(parents=True)\n            session.run(\n                \"tar\",\n                \"-xjf\",\n                f\"{pyodide_artifacts_path}.tar.bz2\",\n                \"-C\",\n                str(pyodide_artifacts_path),\n                \"--strip-components\",\n                \"1\",\n            )\n\n        dist_dir = pyodide_artifacts_path\n    assert dist_dir is not None\n    assert dist_dir.exists()\n    if runner == \"chrome\":\n        # install chrome webdriver and add it to path\n        driver = typing.cast(\n            str,\n            session.run(\n                \"python\",\n                \"-c\",\n                \"from webdriver_manager.chrome import ChromeDriverManager;print(ChromeDriverManager().install())\",\n                silent=True,\n            ),\n        ).strip()\n        session.env[\"PATH\"] = f\"{Path(driver).parent}:{session.env['PATH']}\"\n\n        tests_impl(\n            session,\n            pytest_extra_args=[\n                \"--rt\",\n                \"chrome-no-host\",\n                \"--dist-dir\",\n                str(dist_dir),\n                \"test\",\n            ],\n        )\n    elif runner == \"firefox\":\n        driver = typing.cast(\n            str,\n            session.run(\n                \"python\",\n                \"-c\",\n                \"from webdriver_manager.firefox import GeckoDriverManager;print(GeckoDriverManager().install())\",\n                silent=True,\n            ),\n        ).strip()\n        session.env[\"PATH\"] = f\"{Path(driver).parent}:{session.env['PATH']}\"\n\n        tests_impl(\n            session,\n            pytest_extra_args=[\n                \"--rt\",\n                \"firefox-no-host\",\n                \"--dist-dir\",\n                str(dist_dir),\n                \"test\",\n            ],\n        )\n    else:\n        raise ValueError(f\"Unknown runner: {runner}\")\n\n\n@nox.session(python=\"3.12\")\ndef mypy(session: nox.Session) -> None:\n    \"\"\"Run mypy.\"\"\"\n    session.install(\"-r\", \"mypy-requirements.txt\")\n    session.run(\"mypy\", \"--version\")\n    session.run(\n        \"mypy\",\n        \"-p\",\n        \"dummyserver\",\n        \"-m\",\n        \"noxfile\",\n        \"-p\",\n        \"urllib3\",\n        \"-p\",\n        \"test\",\n    )\n\n\n@nox.session\ndef docs(session: nox.Session) -> None:\n    session.install(\"-r\", \"docs/requirements.txt\")\n    session.install(\".[socks,brotli,zstd]\")\n\n    session.chdir(\"docs\")\n    if os.path.exists(\"_build\"):\n        shutil.rmtree(\"_build\")\n    session.run(\"sphinx-build\", \"-b\", \"html\", \"-W\", \".\", \"_build/html\")\n", "path": "noxfile.py"}], "after_files": [{"content": "from __future__ import annotations\n\nimport os\nimport shutil\nimport sys\nimport typing\nfrom pathlib import Path\n\nimport nox\n\nnox.options.error_on_missing_interpreters = True\n\n\ndef tests_impl(\n    session: nox.Session,\n    extras: str = \"socks,brotli,zstd,h2\",\n    # hypercorn dependency h2 compares bytes and strings\n    # https://github.com/python-hyper/h2/issues/1236\n    byte_string_comparisons: bool = False,\n    integration: bool = False,\n    pytest_extra_args: list[str] = [],\n) -> None:\n    # Retrieve sys info from the Python implementation under test\n    # to avoid enabling memray when nox runs under CPython but tests PyPy\n    session_python_info = session.run(\n        \"python\",\n        \"-c\",\n        \"import sys; print(sys.implementation.name, sys.version_info.releaselevel)\",\n        silent=True,\n    ).strip()  # type: ignore[union-attr] # mypy doesn't know that silent=True  will return a string\n    implementation_name, release_level = session_python_info.split(\" \")\n\n    # zstd cannot be installed on CPython 3.13 yet because it pins\n    # an incompatible CFFI version.\n    # https://github.com/indygreg/python-zstandard/issues/210\n    if release_level != \"final\":\n        extras = extras.replace(\",zstd\", \"\")\n\n    # Install deps and the package itself.\n    session.install(\"-r\", \"dev-requirements.txt\")\n    session.install(f\".[{extras}]\")\n\n    # Show the pip version.\n    session.run(\"pip\", \"--version\")\n    # Print the Python version and bytesize.\n    session.run(\"python\", \"--version\")\n    session.run(\"python\", \"-c\", \"import struct; print(struct.calcsize('P') * 8)\")\n    # Print OpenSSL information.\n    session.run(\"python\", \"-m\", \"OpenSSL.debug\")\n\n    memray_supported = True\n    if implementation_name != \"cpython\" or release_level != \"final\":\n        memray_supported = False  # pytest-memray requires CPython 3.8+\n    elif sys.platform == \"win32\":\n        memray_supported = False\n\n    # Environment variables being passed to the pytest run.\n    pytest_session_envvars = {\n        \"PYTHONWARNINGS\": \"always::DeprecationWarning\",\n    }\n\n    # In coverage 7.4.0 we can only set the setting for Python 3.12+\n    # Future versions of coverage will use sys.monitoring based on availability.\n    if (\n        isinstance(session.python, str)\n        and \".\" in session.python\n        and int(session.python.split(\".\")[1]) >= 12\n    ):\n        pytest_session_envvars[\"COVERAGE_CORE\"] = \"sysmon\"\n\n    # Inspired from https://hynek.me/articles/ditch-codecov-python/\n    # We use parallel mode and then combine in a later CI step\n    session.run(\n        \"python\",\n        *((\"-bb\",) if byte_string_comparisons else ()),\n        \"-m\",\n        \"coverage\",\n        \"run\",\n        \"--parallel-mode\",\n        \"-m\",\n        \"pytest\",\n        *(\"--memray\", \"--hide-memray-summary\") if memray_supported else (),\n        \"-v\",\n        \"-ra\",\n        *((\"--integration\",) if integration else ()),\n        f\"--color={'yes' if 'GITHUB_ACTIONS' in os.environ else 'auto'}\",\n        \"--tb=native\",\n        \"--durations=10\",\n        \"--strict-config\",\n        \"--strict-markers\",\n        *pytest_extra_args,\n        *(session.posargs or (\"test/\",)),\n        env=pytest_session_envvars,\n    )\n\n\n@nox.session(\n    python=[\n        \"3.8\",\n        \"3.9\",\n        \"3.10\",\n        \"3.11\",\n        \"3.12\",\n        \"3.13\",\n        \"pypy3.8\",\n        \"pypy3.9\",\n        \"pypy3.10\",\n    ]\n)\ndef test(session: nox.Session) -> None:\n    tests_impl(session)\n\n\n@nox.session(python=\"3\")\ndef test_integration(session: nox.Session) -> None:\n    \"\"\"Run integration tests\"\"\"\n    tests_impl(session, integration=True)\n\n\n@nox.session(python=\"3\")\ndef test_brotlipy(session: nox.Session) -> None:\n    \"\"\"Check that if 'brotlipy' is installed instead of 'brotli' or\n    'brotlicffi' that we still don't blow up.\n    \"\"\"\n    session.install(\"brotlipy\")\n    tests_impl(session, extras=\"socks\", byte_string_comparisons=False)\n\n\ndef git_clone(session: nox.Session, git_url: str) -> None:\n    \"\"\"We either clone the target repository or if already exist\n    simply reset the state and pull.\n    \"\"\"\n    expected_directory = git_url.split(\"/\")[-1]\n\n    if expected_directory.endswith(\".git\"):\n        expected_directory = expected_directory[:-4]\n\n    if not os.path.isdir(expected_directory):\n        session.run(\"git\", \"clone\", \"--depth\", \"1\", git_url, external=True)\n    else:\n        session.run(\n            \"git\", \"-C\", expected_directory, \"reset\", \"--hard\", \"HEAD\", external=True\n        )\n        session.run(\"git\", \"-C\", expected_directory, \"pull\", external=True)\n\n\n@nox.session()\ndef downstream_botocore(session: nox.Session) -> None:\n    root = os.getcwd()\n    tmp_dir = session.create_tmp()\n\n    session.cd(tmp_dir)\n    git_clone(session, \"https://github.com/boto/botocore\")\n    session.chdir(\"botocore\")\n    session.run(\"git\", \"rev-parse\", \"HEAD\", external=True)\n    session.run(\"python\", \"scripts/ci/install\")\n\n    session.cd(root)\n    session.install(\".\", silent=False)\n    session.cd(f\"{tmp_dir}/botocore\")\n\n    session.run(\"python\", \"-c\", \"import urllib3; print(urllib3.__version__)\")\n    session.run(\"python\", \"scripts/ci/run-tests\")\n\n\n@nox.session()\ndef downstream_requests(session: nox.Session) -> None:\n    root = os.getcwd()\n    tmp_dir = session.create_tmp()\n\n    session.cd(tmp_dir)\n    git_clone(session, \"https://github.com/psf/requests\")\n    session.chdir(\"requests\")\n    session.run(\"git\", \"rev-parse\", \"HEAD\", external=True)\n    session.install(\".[socks]\", silent=False)\n    session.install(\"-r\", \"requirements-dev.txt\", silent=False)\n\n    # Workaround until https://github.com/psf/httpbin/pull/29 gets released\n    session.install(\"flask<3\", \"werkzeug<3\", silent=False)\n\n    session.cd(root)\n    session.install(\".\", silent=False)\n    session.cd(f\"{tmp_dir}/requests\")\n\n    session.run(\"python\", \"-c\", \"import urllib3; print(urllib3.__version__)\")\n    session.run(\"pytest\", \"tests\")\n\n\n@nox.session()\ndef format(session: nox.Session) -> None:\n    \"\"\"Run code formatters.\"\"\"\n    lint(session)\n\n\n@nox.session(python=\"3.12\")\ndef lint(session: nox.Session) -> None:\n    session.install(\"pre-commit\")\n    session.run(\"pre-commit\", \"run\", \"--all-files\")\n\n    mypy(session)\n\n\n@nox.session(python=\"3.11\")\ndef pyodideconsole(session: nox.Session) -> None:\n    # build wheel into dist folder\n    session.install(\"build\")\n    session.run(\"python\", \"-m\", \"build\")\n    session.run(\n        \"cp\",\n        \"test/contrib/emscripten/templates/pyodide-console.html\",\n        \"dist/index.html\",\n        external=True,\n    )\n    session.cd(\"dist\")\n    session.run(\"python\", \"-m\", \"http.server\")\n\n\n# TODO: node support is not tested yet - it should work if you require('xmlhttprequest') before\n# loading pyodide, but there is currently no nice way to do this with pytest-pyodide\n# because you can't override the test runner properties easily - see\n# https://github.com/pyodide/pytest-pyodide/issues/118 for more\n@nox.session(python=\"3.11\")\n@nox.parametrize(\"runner\", [\"firefox\", \"chrome\"])\ndef emscripten(session: nox.Session, runner: str) -> None:\n    \"\"\"Test on Emscripten with Pyodide & Chrome / Firefox\"\"\"\n    session.install(\"-r\", \"emscripten-requirements.txt\")\n    # build wheel into dist folder\n    session.run(\"python\", \"-m\", \"build\")\n    # make sure we have a dist dir for pyodide\n    dist_dir = None\n    if \"PYODIDE_ROOT\" in os.environ:\n        # we have a pyodide build tree checked out\n        # use the dist directory from that\n        dist_dir = Path(os.environ[\"PYODIDE_ROOT\"]) / \"dist\"\n    else:\n        # we don't have a build tree, get one\n        # that matches the version of pyodide build\n        pyodide_version = typing.cast(\n            str,\n            session.run(\n                \"python\",\n                \"-c\",\n                \"import pyodide_build;print(pyodide_build.__version__)\",\n                silent=True,\n            ),\n        ).strip()\n\n        pyodide_artifacts_path = Path(session.cache_dir) / f\"pyodide-{pyodide_version}\"\n        if not pyodide_artifacts_path.exists():\n            print(\"Fetching pyodide build artifacts\")\n            session.run(\n                \"wget\",\n                f\"https://github.com/pyodide/pyodide/releases/download/{pyodide_version}/pyodide-{pyodide_version}.tar.bz2\",\n                \"-O\",\n                f\"{pyodide_artifacts_path}.tar.bz2\",\n            )\n            pyodide_artifacts_path.mkdir(parents=True)\n            session.run(\n                \"tar\",\n                \"-xjf\",\n                f\"{pyodide_artifacts_path}.tar.bz2\",\n                \"-C\",\n                str(pyodide_artifacts_path),\n                \"--strip-components\",\n                \"1\",\n            )\n\n        dist_dir = pyodide_artifacts_path\n    assert dist_dir is not None\n    assert dist_dir.exists()\n    if runner == \"chrome\":\n        # install chrome webdriver and add it to path\n        driver = typing.cast(\n            str,\n            session.run(\n                \"python\",\n                \"-c\",\n                \"from webdriver_manager.chrome import ChromeDriverManager;print(ChromeDriverManager().install())\",\n                silent=True,\n            ),\n        ).strip()\n        session.env[\"PATH\"] = f\"{Path(driver).parent}:{session.env['PATH']}\"\n\n        tests_impl(\n            session,\n            pytest_extra_args=[\n                \"--rt\",\n                \"chrome-no-host\",\n                \"--dist-dir\",\n                str(dist_dir),\n                \"test\",\n            ],\n        )\n    elif runner == \"firefox\":\n        driver = typing.cast(\n            str,\n            session.run(\n                \"python\",\n                \"-c\",\n                \"from webdriver_manager.firefox import GeckoDriverManager;print(GeckoDriverManager().install())\",\n                silent=True,\n            ),\n        ).strip()\n        session.env[\"PATH\"] = f\"{Path(driver).parent}:{session.env['PATH']}\"\n\n        tests_impl(\n            session,\n            pytest_extra_args=[\n                \"--rt\",\n                \"firefox-no-host\",\n                \"--dist-dir\",\n                str(dist_dir),\n                \"test\",\n            ],\n        )\n    else:\n        raise ValueError(f\"Unknown runner: {runner}\")\n\n\n@nox.session(python=\"3.12\")\ndef mypy(session: nox.Session) -> None:\n    \"\"\"Run mypy.\"\"\"\n    session.install(\"-r\", \"mypy-requirements.txt\")\n    session.run(\"mypy\", \"--version\")\n    session.run(\n        \"mypy\",\n        \"-p\",\n        \"dummyserver\",\n        \"-m\",\n        \"noxfile\",\n        \"-p\",\n        \"urllib3\",\n        \"-p\",\n        \"test\",\n    )\n\n\n@nox.session\ndef docs(session: nox.Session) -> None:\n    session.install(\"-r\", \"docs/requirements.txt\")\n    session.install(\".[socks,brotli,zstd]\")\n\n    session.chdir(\"docs\")\n    if os.path.exists(\"_build\"):\n        shutil.rmtree(\"_build\")\n    session.run(\"sphinx-build\", \"-b\", \"html\", \"-W\", \".\", \"_build/html\")\n", "path": "noxfile.py"}]}