From 5b4de369898d6f0132688799e5d919bcff4c9f20 Mon Sep 17 00:00:00 2001 From: barneygale Date: Sun, 20 Jul 2025 15:56:27 +0100 Subject: [PATCH 1/2] GH-136874: `url2pathname()`: discard query and fragment components In `urllib.request.url2pathname()`, ignore any query or fragment components in the given URL. --- Doc/library/urllib.request.rst | 3 +++ Doc/whatsnew/3.14.rst | 1 + Lib/test/test_urllib.py | 4 ++++ Lib/urllib/request.py | 10 +++++----- .../2025-07-20-16-02-00.gh-issue-136874.cLC3o1.rst | 1 + 5 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-07-20-16-02-00.gh-issue-136874.cLC3o1.rst diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst index 1e716715fd9bed..e514b98fc5d553 100644 --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -210,6 +210,9 @@ The :mod:`urllib.request` module defines the following functions: Windows a UNC path is returned (as before), and on other platforms a :exc:`~urllib.error.URLError` is raised. + .. versionchanged:: 3.14 + The URL query and fragment components are discarded if present. + .. versionchanged:: 3.14 The *require_scheme* and *resolve_host* parameters were added. diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index 6ddc77d8f95038..560bc2f8ec78f3 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -2193,6 +2193,7 @@ urllib - Discard URL authority if it matches the local hostname. - Discard URL authority if it resolves to a local IP address when the new *resolve_host* argument is set to true. + - Discard URL query and fragment components. - Raise :exc:`~urllib.error.URLError` if a URL authority isn't local, except on Windows where we return a UNC path as before. diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py index 1d889ae7cf458f..81acd6fea7da11 100644 --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -1526,6 +1526,10 @@ def test_url2pathname(self): self.assertEqual(fn('////foo/bar'), f'{sep}{sep}foo{sep}bar') self.assertEqual(fn('data:blah'), 'data:blah') self.assertEqual(fn('data://blah'), f'data:{sep}{sep}blah') + self.assertEqual(fn('foo?bar'), 'foo') + self.assertEqual(fn('foo#bar'), 'foo') + self.assertEqual(fn('foo?bar=baz'), 'foo') + self.assertEqual(fn('foo?bar#baz'), 'foo') def test_url2pathname_require_scheme(self): sep = os.path.sep diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py index 41dc5d7b35dedb..c1c373d08815c1 100644 --- a/Lib/urllib/request.py +++ b/Lib/urllib/request.py @@ -1654,11 +1654,11 @@ def url2pathname(url, *, require_scheme=False, resolve_host=False): The URL authority may be resolved with gethostbyname() if *resolve_host* is set to true. """ - if require_scheme: - scheme, url = _splittype(url) - if scheme != 'file': - raise URLError("URL is missing a 'file:' scheme") - authority, url = _splithost(url) + if not require_scheme: + url = 'file:' + url + scheme, authority, url = urlsplit(url)[:3] # Discard query and fragment. + if scheme != 'file': + raise URLError("URL is missing a 'file:' scheme") if os.name == 'nt': if not _is_local_authority(authority, resolve_host): # e.g. file://server/share/file.txt diff --git a/Misc/NEWS.d/next/Library/2025-07-20-16-02-00.gh-issue-136874.cLC3o1.rst b/Misc/NEWS.d/next/Library/2025-07-20-16-02-00.gh-issue-136874.cLC3o1.rst new file mode 100644 index 00000000000000..9a71eb8ef1ac8d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-07-20-16-02-00.gh-issue-136874.cLC3o1.rst @@ -0,0 +1 @@ +Discard URL query and fragment in :func:`urllib.request.url2pathname`. From 100330de278a0ef32b72900ba481a5963548f036 Mon Sep 17 00:00:00 2001 From: barneygale Date: Mon, 21 Jul 2025 18:07:18 +0100 Subject: [PATCH 2/2] Test cases for percent-encoded `?` and `#` --- Lib/test/test_urllib.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py index 81acd6fea7da11..c30fb5e27eea8a 100644 --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -1530,6 +1530,10 @@ def test_url2pathname(self): self.assertEqual(fn('foo#bar'), 'foo') self.assertEqual(fn('foo?bar=baz'), 'foo') self.assertEqual(fn('foo?bar#baz'), 'foo') + self.assertEqual(fn('foo%3Fbar'), 'foo?bar') + self.assertEqual(fn('foo%23bar'), 'foo#bar') + self.assertEqual(fn('foo%3Fbar%3Dbaz'), 'foo?bar=baz') + self.assertEqual(fn('foo%3Fbar%23baz'), 'foo?bar#baz') def test_url2pathname_require_scheme(self): sep = os.path.sep pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy