mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
GH-125866: Deprecate nturl2path
module (#131432)
Deprecate the `nturl2path` module. Its functionality is merged into `urllib.request`. Add `tests.test_nturl2path` to exercise `nturl2path`, as it's no longer covered by `test_urllib`.
This commit is contained in:
parent
8a33034d82
commit
8abfaba5a6
6 changed files with 179 additions and 34 deletions
|
@ -1148,6 +1148,11 @@ Deprecated
|
||||||
or *sequence* as keyword arguments is now deprecated.
|
or *sequence* as keyword arguments is now deprecated.
|
||||||
(Contributed by Kirill Podoprigora in :gh:`121676`.)
|
(Contributed by Kirill Podoprigora in :gh:`121676`.)
|
||||||
|
|
||||||
|
* :mod:`!nturl2path`: This module is now deprecated. Call
|
||||||
|
:func:`urllib.request.url2pathname` and :func:`~urllib.request.pathname2url`
|
||||||
|
instead.
|
||||||
|
(Contributed by Barney Gale in :gh:`125866`.)
|
||||||
|
|
||||||
* :mod:`os`:
|
* :mod:`os`:
|
||||||
:term:`Soft deprecate <soft deprecated>` :func:`os.popen` and
|
:term:`Soft deprecate <soft deprecated>` :func:`os.popen` and
|
||||||
:func:`os.spawn* <os.spawnl>` functions. They should no longer be used to
|
:func:`os.spawn* <os.spawnl>` functions. They should no longer be used to
|
||||||
|
|
|
@ -3,7 +3,15 @@
|
||||||
This module only exists to provide OS-specific code
|
This module only exists to provide OS-specific code
|
||||||
for urllib.requests, thus do not use directly.
|
for urllib.requests, thus do not use directly.
|
||||||
"""
|
"""
|
||||||
# Testing is done through test_urllib.
|
# Testing is done through test_nturl2path.
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
|
||||||
|
warnings._deprecated(
|
||||||
|
__name__,
|
||||||
|
message=f"{warnings._DEPRECATED_MSG}; use 'urllib.request' instead",
|
||||||
|
remove=(3, 19))
|
||||||
|
|
||||||
def url2pathname(url):
|
def url2pathname(url):
|
||||||
"""OS-specific conversion from a relative URL of the 'file' scheme
|
"""OS-specific conversion from a relative URL of the 'file' scheme
|
||||||
|
|
107
Lib/test/test_nturl2path.py
Normal file
107
Lib/test/test_nturl2path.py
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from test.support import warnings_helper
|
||||||
|
|
||||||
|
|
||||||
|
nturl2path = warnings_helper.import_deprecated("nturl2path")
|
||||||
|
|
||||||
|
|
||||||
|
class NTURL2PathTest(unittest.TestCase):
|
||||||
|
"""Test pathname2url() and url2pathname()"""
|
||||||
|
|
||||||
|
def test_basic(self):
|
||||||
|
# Make sure simple tests pass
|
||||||
|
expected_path = r"parts\of\a\path"
|
||||||
|
expected_url = "parts/of/a/path"
|
||||||
|
result = nturl2path.pathname2url(expected_path)
|
||||||
|
self.assertEqual(expected_url, result,
|
||||||
|
"pathname2url() failed; %s != %s" %
|
||||||
|
(result, expected_url))
|
||||||
|
result = nturl2path.url2pathname(expected_url)
|
||||||
|
self.assertEqual(expected_path, result,
|
||||||
|
"url2pathame() failed; %s != %s" %
|
||||||
|
(result, expected_path))
|
||||||
|
|
||||||
|
def test_pathname2url(self):
|
||||||
|
# Test special prefixes are correctly handled in pathname2url()
|
||||||
|
fn = nturl2path.pathname2url
|
||||||
|
self.assertEqual(fn('\\\\?\\C:\\dir'), '///C:/dir')
|
||||||
|
self.assertEqual(fn('\\\\?\\unc\\server\\share\\dir'), '//server/share/dir')
|
||||||
|
self.assertEqual(fn("C:"), '///C:')
|
||||||
|
self.assertEqual(fn("C:\\"), '///C:/')
|
||||||
|
self.assertEqual(fn('c:\\a\\b.c'), '///c:/a/b.c')
|
||||||
|
self.assertEqual(fn('C:\\a\\b.c'), '///C:/a/b.c')
|
||||||
|
self.assertEqual(fn('C:\\a\\b.c\\'), '///C:/a/b.c/')
|
||||||
|
self.assertEqual(fn('C:\\a\\\\b.c'), '///C:/a//b.c')
|
||||||
|
self.assertEqual(fn('C:\\a\\b%#c'), '///C:/a/b%25%23c')
|
||||||
|
self.assertEqual(fn('C:\\a\\b\xe9'), '///C:/a/b%C3%A9')
|
||||||
|
self.assertEqual(fn('C:\\foo\\bar\\spam.foo'), "///C:/foo/bar/spam.foo")
|
||||||
|
# NTFS alternate data streams
|
||||||
|
self.assertEqual(fn('C:\\foo:bar'), '///C:/foo%3Abar')
|
||||||
|
self.assertEqual(fn('foo:bar'), 'foo%3Abar')
|
||||||
|
# No drive letter
|
||||||
|
self.assertEqual(fn("\\folder\\test\\"), '///folder/test/')
|
||||||
|
self.assertEqual(fn("\\\\folder\\test\\"), '//folder/test/')
|
||||||
|
self.assertEqual(fn("\\\\\\folder\\test\\"), '///folder/test/')
|
||||||
|
self.assertEqual(fn('\\\\some\\share\\'), '//some/share/')
|
||||||
|
self.assertEqual(fn('\\\\some\\share\\a\\b.c'), '//some/share/a/b.c')
|
||||||
|
self.assertEqual(fn('\\\\some\\share\\a\\b%#c\xe9'), '//some/share/a/b%25%23c%C3%A9')
|
||||||
|
# Alternate path separator
|
||||||
|
self.assertEqual(fn('C:/a/b.c'), '///C:/a/b.c')
|
||||||
|
self.assertEqual(fn('//some/share/a/b.c'), '//some/share/a/b.c')
|
||||||
|
self.assertEqual(fn('//?/C:/dir'), '///C:/dir')
|
||||||
|
self.assertEqual(fn('//?/unc/server/share/dir'), '//server/share/dir')
|
||||||
|
# Round-tripping
|
||||||
|
urls = ['///C:',
|
||||||
|
'///folder/test/',
|
||||||
|
'///C:/foo/bar/spam.foo']
|
||||||
|
for url in urls:
|
||||||
|
self.assertEqual(fn(nturl2path.url2pathname(url)), url)
|
||||||
|
|
||||||
|
def test_url2pathname(self):
|
||||||
|
fn = nturl2path.url2pathname
|
||||||
|
self.assertEqual(fn('/'), '\\')
|
||||||
|
self.assertEqual(fn('/C:/'), 'C:\\')
|
||||||
|
self.assertEqual(fn("///C|"), 'C:')
|
||||||
|
self.assertEqual(fn("///C:"), 'C:')
|
||||||
|
self.assertEqual(fn('///C:/'), 'C:\\')
|
||||||
|
self.assertEqual(fn('/C|//'), 'C:\\\\')
|
||||||
|
self.assertEqual(fn('///C|/path'), 'C:\\path')
|
||||||
|
# No DOS drive
|
||||||
|
self.assertEqual(fn("///C/test/"), '\\C\\test\\')
|
||||||
|
self.assertEqual(fn("////C/test/"), '\\\\C\\test\\')
|
||||||
|
# DOS drive paths
|
||||||
|
self.assertEqual(fn('c:/path/to/file'), 'c:\\path\\to\\file')
|
||||||
|
self.assertEqual(fn('C:/path/to/file'), 'C:\\path\\to\\file')
|
||||||
|
self.assertEqual(fn('C:/path/to/file/'), 'C:\\path\\to\\file\\')
|
||||||
|
self.assertEqual(fn('C:/path/to//file'), 'C:\\path\\to\\\\file')
|
||||||
|
self.assertEqual(fn('C|/path/to/file'), 'C:\\path\\to\\file')
|
||||||
|
self.assertEqual(fn('/C|/path/to/file'), 'C:\\path\\to\\file')
|
||||||
|
self.assertEqual(fn('///C|/path/to/file'), 'C:\\path\\to\\file')
|
||||||
|
self.assertEqual(fn("///C|/foo/bar/spam.foo"), 'C:\\foo\\bar\\spam.foo')
|
||||||
|
# Colons in URI
|
||||||
|
self.assertEqual(fn('///\u00e8|/'), '\u00e8:\\')
|
||||||
|
self.assertEqual(fn('//host/share/spam.txt:eggs'), '\\\\host\\share\\spam.txt:eggs')
|
||||||
|
self.assertEqual(fn('///c:/spam.txt:eggs'), 'c:\\spam.txt:eggs')
|
||||||
|
# UNC paths
|
||||||
|
self.assertEqual(fn('//server/path/to/file'), '\\\\server\\path\\to\\file')
|
||||||
|
self.assertEqual(fn('////server/path/to/file'), '\\\\server\\path\\to\\file')
|
||||||
|
self.assertEqual(fn('/////server/path/to/file'), '\\\\server\\path\\to\\file')
|
||||||
|
# Localhost paths
|
||||||
|
self.assertEqual(fn('//localhost/C:/path/to/file'), 'C:\\path\\to\\file')
|
||||||
|
self.assertEqual(fn('//localhost/C|/path/to/file'), 'C:\\path\\to\\file')
|
||||||
|
self.assertEqual(fn('//localhost/path/to/file'), '\\path\\to\\file')
|
||||||
|
self.assertEqual(fn('//localhost//server/path/to/file'), '\\\\server\\path\\to\\file')
|
||||||
|
# Percent-encoded forward slashes are preserved for backwards compatibility
|
||||||
|
self.assertEqual(fn('C:/foo%2fbar'), 'C:\\foo/bar')
|
||||||
|
self.assertEqual(fn('//server/share/foo%2fbar'), '\\\\server\\share\\foo/bar')
|
||||||
|
# Round-tripping
|
||||||
|
paths = ['C:',
|
||||||
|
r'\C\test\\',
|
||||||
|
r'C:\foo\bar\spam.foo']
|
||||||
|
for path in paths:
|
||||||
|
self.assertEqual(fn(nturl2path.pathname2url(path)), path)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
|
@ -44,10 +44,6 @@ class TrivialTests(unittest.TestCase):
|
||||||
context = {}
|
context = {}
|
||||||
exec('from urllib.%s import *' % module, context)
|
exec('from urllib.%s import *' % module, context)
|
||||||
del context['__builtins__']
|
del context['__builtins__']
|
||||||
if module == 'request' and os.name == 'nt':
|
|
||||||
u, p = context.pop('url2pathname'), context.pop('pathname2url')
|
|
||||||
self.assertEqual(u.__module__, 'nturl2path')
|
|
||||||
self.assertEqual(p.__module__, 'nturl2path')
|
|
||||||
for k, v in context.items():
|
for k, v in context.items():
|
||||||
self.assertEqual(v.__module__, 'urllib.%s' % module,
|
self.assertEqual(v.__module__, 'urllib.%s' % module,
|
||||||
"%r is exposed in 'urllib.%s' but defined in %r" %
|
"%r is exposed in 'urllib.%s' but defined in %r" %
|
||||||
|
|
|
@ -1646,36 +1646,62 @@ class DataHandler(BaseHandler):
|
||||||
|
|
||||||
# Code move from the old urllib module
|
# Code move from the old urllib module
|
||||||
|
|
||||||
# Helper for non-unix systems
|
def url2pathname(url):
|
||||||
if os.name == 'nt':
|
"""OS-specific conversion from a relative URL of the 'file' scheme
|
||||||
from nturl2path import url2pathname, pathname2url
|
to a file system path; not recommended for general use."""
|
||||||
else:
|
if url[:3] == '///':
|
||||||
def url2pathname(pathname):
|
# Empty authority section, so the path begins on the third character.
|
||||||
"""OS-specific conversion from a relative URL of the 'file' scheme
|
url = url[2:]
|
||||||
to a file system path; not recommended for general use."""
|
elif url[:12] == '//localhost/':
|
||||||
if pathname[:3] == '///':
|
# Skip past 'localhost' authority.
|
||||||
# URL has an empty authority section, so the path begins on the
|
url = url[11:]
|
||||||
# third character.
|
|
||||||
pathname = pathname[2:]
|
|
||||||
elif pathname[:12] == '//localhost/':
|
|
||||||
# Skip past 'localhost' authority.
|
|
||||||
pathname = pathname[11:]
|
|
||||||
encoding = sys.getfilesystemencoding()
|
|
||||||
errors = sys.getfilesystemencodeerrors()
|
|
||||||
return unquote(pathname, encoding=encoding, errors=errors)
|
|
||||||
|
|
||||||
def pathname2url(pathname):
|
if os.name == 'nt':
|
||||||
"""OS-specific conversion from a file system path to a relative URL
|
if url[:3] == '///':
|
||||||
of the 'file' scheme; not recommended for general use."""
|
# Skip past extra slash before UNC drive in URL path.
|
||||||
if pathname[:1] == '/':
|
url = url[1:]
|
||||||
# Add explicitly empty authority to absolute path. If the path
|
else:
|
||||||
# starts with exactly one slash then this change is mostly
|
if url[:1] == '/' and url[2:3] in (':', '|'):
|
||||||
# cosmetic, but if it begins with two or more slashes then this
|
# Skip past extra slash before DOS drive in URL path.
|
||||||
# avoids interpreting the path as a URL authority.
|
url = url[1:]
|
||||||
pathname = '//' + pathname
|
if url[1:2] == '|':
|
||||||
encoding = sys.getfilesystemencoding()
|
# Older URLs use a pipe after a drive letter
|
||||||
errors = sys.getfilesystemencodeerrors()
|
url = url[:1] + ':' + url[2:]
|
||||||
return quote(pathname, encoding=encoding, errors=errors)
|
url = url.replace('/', '\\')
|
||||||
|
encoding = sys.getfilesystemencoding()
|
||||||
|
errors = sys.getfilesystemencodeerrors()
|
||||||
|
return unquote(url, encoding=encoding, errors=errors)
|
||||||
|
|
||||||
|
|
||||||
|
def pathname2url(pathname):
|
||||||
|
"""OS-specific conversion from a file system path to a relative URL
|
||||||
|
of the 'file' scheme; not recommended for general use."""
|
||||||
|
if os.name == 'nt':
|
||||||
|
pathname = pathname.replace('\\', '/')
|
||||||
|
encoding = sys.getfilesystemencoding()
|
||||||
|
errors = sys.getfilesystemencodeerrors()
|
||||||
|
drive, root, tail = os.path.splitroot(pathname)
|
||||||
|
if drive:
|
||||||
|
# First, clean up some special forms. We are going to sacrifice the
|
||||||
|
# additional information anyway
|
||||||
|
if drive[:4] == '//?/':
|
||||||
|
drive = drive[4:]
|
||||||
|
if drive[:4].upper() == 'UNC/':
|
||||||
|
drive = '//' + drive[4:]
|
||||||
|
if drive[1:] == ':':
|
||||||
|
# DOS drive specified. Add three slashes to the start, producing
|
||||||
|
# an authority section with a zero-length authority, and a path
|
||||||
|
# section starting with a single slash.
|
||||||
|
drive = '///' + drive
|
||||||
|
drive = quote(drive, encoding=encoding, errors=errors, safe='/:')
|
||||||
|
elif root:
|
||||||
|
# Add explicitly empty authority to absolute path. If the path
|
||||||
|
# starts with exactly one slash then this change is mostly
|
||||||
|
# cosmetic, but if it begins with two or more slashes then this
|
||||||
|
# avoids interpreting the path as a URL authority.
|
||||||
|
root = '//' + root
|
||||||
|
tail = quote(tail, encoding=encoding, errors=errors)
|
||||||
|
return drive + root + tail
|
||||||
|
|
||||||
|
|
||||||
# Utility functions
|
# Utility functions
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Deprecate the :mod:`!nturl2path` module. Call
|
||||||
|
:func:`urllib.request.url2pathname` and :func:`~urllib.request.pathname2url`
|
||||||
|
instead.
|
Loading…
Add table
Add a link
Reference in a new issue