Skip to content

gh-119671: Add os.path.pure #119772

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,10 @@
# Undocumented modules that users shouldn't have to worry about
# (implementation details of `os.path`):
('py:mod', 'ntpath'),
('py:mod', 'ntpath.pure'),
('py:mod', 'posixpath'),
('py:mod', 'posixpath.pure'),
('py:mod', 'os.path.pure'),
]

# Temporary undocumented names.
Expand Down
8 changes: 4 additions & 4 deletions Doc/library/os.path.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
.. module:: os.path
:synopsis: Operations on pathnames.

**Source code:** :source:`Lib/genericpath.py`, :source:`Lib/posixpath.py` (for POSIX) and
:source:`Lib/ntpath.py` (for Windows).
**Source code:** :source:`Lib/genericpath.py`, :source:`Lib/posixpath/` (for POSIX) and
:source:`Lib/ntpath/` (for Windows).

.. index:: single: path; operations

Expand Down Expand Up @@ -42,8 +42,8 @@ the :mod:`glob` module.)
a path that is *always* in one of the different formats. They all have the
same interface:

* :mod:`posixpath` for UNIX-style paths
* :mod:`ntpath` for Windows paths
* :mod:`posixpath.pure` for UNIX-style paths
* :mod:`ntpath.pure` for Windows paths


.. versionchanged:: 3.8
Expand Down
File renamed without changes.
22 changes: 22 additions & 0 deletions Lib/ntpath/pure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Module 'ntpath.pure' -- pure operations on WinNT/Win95 pathnames
"""Pure pathname manipulations, WindowsNT/95 version."""
import os
import ntpath
from ntpath import (altsep, basename, commonpath, commonprefix, curdir,
dirname, extsep, isabs, isreserved, join, normcase,
normpath, pardir, pathsep, sep, split, splitdrive,
splitext, splitroot)

__all__ = ["altsep", "basename", "commonpath", "commonprefix", "curdir",
"dirname", "extsep", "isabs", "isreserved", "join", "normcase",
"normpath", "pardir", "pathsep", "relpath", "sep", "split",
"splitdrive", "splitext", "splitroot"]

def relpath(path, start):
"""Return a relative version of a path"""
path = os.fspath(path)
start = os.fspath(start)
if not isabs(path) or not isabs(start):
raise ValueError("paths are not absolute")

return ntpath.relpath(path, start)
3 changes: 0 additions & 3 deletions Lib/posixpath.py → Lib/posixpath/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
module on Posix systems; on other systems (e.g. Windows),
os.path provides the same operations in a manner specific to that
platform, and is an alias to another module (e.g. ntpath).

Some of this can actually be useful on non-Posix systems too, e.g.
for manipulation of the pathname component of URLs.
"""

# Strings representing various path-related bits and pieces.
Expand Down
25 changes: 25 additions & 0 deletions Lib/posixpath/pure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""Pure operations on Posix pathnames.

This can actually be useful on non-Posix systems too, e.g.
for manipulation of the pathname component of URLs.
"""
import os
import posixpath
from posixpath import (altsep, basename, commonpath, commonprefix, curdir,
dirname, extsep, isabs, join, normcase, normpath,
pardir, pathsep, sep, split, splitdrive, splitext,
splitroot)

__all__ = ["altsep", "basename", "commonpath", "commonprefix", "curdir",
"dirname", "extsep", "isabs", "join", "normcase", "normpath",
"pardir", "pathsep", "relpath", "sep", "split", "splitdrive",
"splitext", "splitroot"]

def relpath(path, start):
"""Return a relative version of a path"""
path = os.fspath(path)
start = os.fspath(start)
if not isabs(path) or not isabs(start):
raise ValueError("paths are not absolute")

return posixpath.relpath(path, start)
12 changes: 12 additions & 0 deletions Lib/test/test_ntpath.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import inspect
import ntpath
import ntpath.pure
import os
import string
import subprocess
Expand Down Expand Up @@ -863,6 +864,17 @@ def test_relpath(self):
tester('ntpath.relpath("/a/b", "/a/b")', '.')
tester('ntpath.relpath("c:/foo", "C:/FOO")', '.')

def test_pure_relpath(self):
self.assertRaises(ValueError, ntpath.pure.relpath, 'foo', 'bar')
self.assertRaises(ValueError, ntpath.pure.relpath, 'foo', 'C:/bar')
self.assertRaises(ValueError, ntpath.pure.relpath, 'C:/foo', 'bar')
tester('ntpath.pure.relpath("C:/foo", "C:/bar")', r'..\foo')

# test bytes
self.assertRaises(ValueError, ntpath.pure.relpath, b'foo', b'bar')
self.assertRaises(ValueError, ntpath.pure.relpath, b'foo', b'C:/bar')
self.assertRaises(ValueError, ntpath.pure.relpath, b'C:/foo', b'bar')

def test_commonpath(self):
def check(paths, expected):
tester(('ntpath.commonpath(%r)' % paths).replace('\\\\', '\\'),
Expand Down
13 changes: 13 additions & 0 deletions Lib/test/test_posixpath.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import inspect
import os
import posixpath
import posixpath.pure
import sys
import unittest
from posixpath import realpath, abspath, dirname, basename
Expand Down Expand Up @@ -746,6 +747,18 @@ def test_relpath_bytes(self):
finally:
os.getcwdb = real_getcwdb

def test_pure_relpath(self):
self.assertRaises(ValueError, posixpath.pure.relpath, 'foo', 'bar')
self.assertRaises(ValueError, posixpath.pure.relpath, 'foo', '/bar')
self.assertRaises(ValueError, posixpath.pure.relpath, '/foo', 'bar')
self.assertEqual(posixpath.pure.relpath('/foo', '/bar'), '../foo')

def test_pure_relpath_bytes(self):
self.assertRaises(ValueError, posixpath.pure.relpath, b'foo', b'bar')
self.assertRaises(ValueError, posixpath.pure.relpath, b'foo', b'/bar')
self.assertRaises(ValueError, posixpath.pure.relpath, b'/foo', b'bar')
self.assertEqual(posixpath.pure.relpath(b'/foo', b'/bar'), b'../foo')

def test_commonpath(self):
def check(paths, expected):
self.assertEqual(posixpath.commonpath(paths), expected)
Expand Down
22 changes: 16 additions & 6 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -1468,8 +1468,10 @@ FROZEN_FILES_IN = \
Lib/_collections_abc.py \
Lib/_sitebuiltins.py \
Lib/genericpath.py \
Lib/ntpath.py \
Lib/posixpath.py \
Lib/ntpath/__init__.py \
Lib/ntpath/pure.py \
Lib/posixpath/__init__.py \
Lib/posixpath/pure.py \
Lib/os.py \
Lib/site.py \
Lib/stat.py \
Expand All @@ -1494,7 +1496,9 @@ FROZEN_FILES_OUT = \
Python/frozen_modules/_sitebuiltins.h \
Python/frozen_modules/genericpath.h \
Python/frozen_modules/ntpath.h \
Python/frozen_modules/ntpath.pure.h \
Python/frozen_modules/posixpath.h \
Python/frozen_modules/posixpath.pure.h \
Python/frozen_modules/os.h \
Python/frozen_modules/site.h \
Python/frozen_modules/stat.h \
Expand Down Expand Up @@ -1549,11 +1553,17 @@ Python/frozen_modules/_sitebuiltins.h: Lib/_sitebuiltins.py $(FREEZE_MODULE_DEPS
Python/frozen_modules/genericpath.h: Lib/genericpath.py $(FREEZE_MODULE_DEPS)
$(FREEZE_MODULE) genericpath $(srcdir)/Lib/genericpath.py Python/frozen_modules/genericpath.h

Python/frozen_modules/ntpath.h: Lib/ntpath.py $(FREEZE_MODULE_DEPS)
$(FREEZE_MODULE) ntpath $(srcdir)/Lib/ntpath.py Python/frozen_modules/ntpath.h
Python/frozen_modules/ntpath.h: Lib/ntpath/__init__.py $(FREEZE_MODULE_DEPS)
$(FREEZE_MODULE) ntpath $(srcdir)/Lib/ntpath/__init__.py Python/frozen_modules/ntpath.h

Python/frozen_modules/posixpath.h: Lib/posixpath.py $(FREEZE_MODULE_DEPS)
$(FREEZE_MODULE) posixpath $(srcdir)/Lib/posixpath.py Python/frozen_modules/posixpath.h
Python/frozen_modules/ntpath.pure.h: Lib/ntpath/pure.py $(FREEZE_MODULE_DEPS)
$(FREEZE_MODULE) ntpath.pure $(srcdir)/Lib/ntpath/pure.py Python/frozen_modules/ntpath.pure.h

Python/frozen_modules/posixpath.h: Lib/posixpath/__init__.py $(FREEZE_MODULE_DEPS)
$(FREEZE_MODULE) posixpath $(srcdir)/Lib/posixpath/__init__.py Python/frozen_modules/posixpath.h

Python/frozen_modules/posixpath.pure.h: Lib/posixpath/pure.py $(FREEZE_MODULE_DEPS)
$(FREEZE_MODULE) posixpath.pure $(srcdir)/Lib/posixpath/pure.py Python/frozen_modules/posixpath.pure.h

Python/frozen_modules/os.h: Lib/os.py $(FREEZE_MODULE_DEPS)
$(FREEZE_MODULE) os $(srcdir)/Lib/os.py Python/frozen_modules/os.h
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add the :mod:`ntpath.pure`, :mod:`os.path.pure`, :mod:`posixpath.pure` modules for low-level path manipulation.
16 changes: 14 additions & 2 deletions PCbuild/_freeze_module.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -318,16 +318,26 @@
<IntFile>$(IntDir)genericpath.g.h</IntFile>
<OutFile>$(GeneratedFrozenModulesDir)Python\frozen_modules\genericpath.h</OutFile>
</None>
<None Include="..\Lib\ntpath.py">
<None Include="..\Lib\ntpath\__init__.py">
<ModName>ntpath</ModName>
<IntFile>$(IntDir)ntpath.g.h</IntFile>
<OutFile>$(GeneratedFrozenModulesDir)Python\frozen_modules\ntpath.h</OutFile>
</None>
<None Include="..\Lib\posixpath.py">
<None Include="..\Lib\ntpath\pure.py">
<ModName>ntpath.pure</ModName>
<IntFile>$(IntDir)ntpath.pure.g.h</IntFile>
<OutFile>$(GeneratedFrozenModulesDir)Python\frozen_modules\ntpath.pure.h</OutFile>
</None>
<None Include="..\Lib\posixpath\__init__.py">
<ModName>posixpath</ModName>
<IntFile>$(IntDir)posixpath.g.h</IntFile>
<OutFile>$(GeneratedFrozenModulesDir)Python\frozen_modules\posixpath.h</OutFile>
</None>
<None Include="..\Lib\posixpath\pure.py">
<ModName>posixpath.pure</ModName>
<IntFile>$(IntDir)posixpath.pure.g.h</IntFile>
<OutFile>$(GeneratedFrozenModulesDir)Python\frozen_modules\posixpath.pure.h</OutFile>
</None>
<None Include="..\Lib\os.py">
<ModName>os</ModName>
<IntFile>$(IntDir)os.g.h</IntFile>
Expand Down Expand Up @@ -410,7 +420,9 @@
<FrozenModule Include="$(GeneratedFrozenModulesDir)Python\frozen_modules\_sitebuiltins.h" FrozenId="_sitebuiltins" />
<FrozenModule Include="$(GeneratedFrozenModulesDir)Python\frozen_modules\genericpath.h" FrozenId="genericpath" />
<FrozenModule Include="$(GeneratedFrozenModulesDir)Python\frozen_modules\ntpath.h" FrozenId="ntpath" />
<FrozenModule Include="$(GeneratedFrozenModulesDir)Python\frozen_modules\ntpath.pure.h" FrozenId="ntpath.pure" />
<FrozenModule Include="$(GeneratedFrozenModulesDir)Python\frozen_modules\posixpath.h" FrozenId="posixpath" />
<FrozenModule Include="$(GeneratedFrozenModulesDir)Python\frozen_modules\posixpath.pure.h" FrozenId="posixpath.pure" />
<FrozenModule Include="$(GeneratedFrozenModulesDir)Python\frozen_modules\os.h" FrozenId="os" />
<FrozenModule Include="$(GeneratedFrozenModulesDir)Python\frozen_modules\site.h" FrozenId="site" />
<FrozenModule Include="$(GeneratedFrozenModulesDir)Python\frozen_modules\stat.h" FrozenId="stat" />
Expand Down
10 changes: 8 additions & 2 deletions PCbuild/_freeze_module.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -523,10 +523,16 @@
<None Include="..\Lib\genericpath.py">
<Filter>Python Files</Filter>
</None>
<None Include="..\Lib\ntpath.py">
<None Include="..\Lib\ntpath\__init__.py">
<Filter>Python Files</Filter>
</None>
<None Include="..\Lib\posixpath.py">
<None Include="..\Lib\ntpath\pure.py">
<Filter>Python Files</Filter>
</None>
<None Include="..\Lib\posixpath\__init__.py">
<Filter>Python Files</Filter>
</None>
<None Include="..\Lib\posixpath\pure.py">
<Filter>Python Files</Filter>
</None>
<None Include="..\Lib\os.py">
Expand Down
14 changes: 10 additions & 4 deletions Python/frozen.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@
#include "frozen_modules/_sitebuiltins.h"
#include "frozen_modules/genericpath.h"
#include "frozen_modules/ntpath.h"
#include "frozen_modules/ntpath.pure.h"
#include "frozen_modules/posixpath.h"
#include "frozen_modules/posixpath.pure.h"
#include "frozen_modules/os.h"
#include "frozen_modules/site.h"
#include "frozen_modules/stat.h"
Expand Down Expand Up @@ -82,9 +84,12 @@ static const struct _frozen stdlib_modules[] = {
{"_collections_abc", _Py_M___collections_abc, (int)sizeof(_Py_M___collections_abc), false},
{"_sitebuiltins", _Py_M___sitebuiltins, (int)sizeof(_Py_M___sitebuiltins), false},
{"genericpath", _Py_M__genericpath, (int)sizeof(_Py_M__genericpath), false},
{"ntpath", _Py_M__ntpath, (int)sizeof(_Py_M__ntpath), false},
{"posixpath", _Py_M__posixpath, (int)sizeof(_Py_M__posixpath), false},
{"os.path", _Py_M__posixpath, (int)sizeof(_Py_M__posixpath), false},
{"ntpath", _Py_M__ntpath, (int)sizeof(_Py_M__ntpath), true},
{"ntpath.pure", _Py_M__ntpath_pure, (int)sizeof(_Py_M__ntpath_pure), false},
{"posixpath", _Py_M__posixpath, (int)sizeof(_Py_M__posixpath), true},
{"posixpath.pure", _Py_M__posixpath_pure, (int)sizeof(_Py_M__posixpath_pure), false},
{"os.path", _Py_M__posixpath, (int)sizeof(_Py_M__posixpath), true},
{"os.path.pure", _Py_M__posixpath_pure, (int)sizeof(_Py_M__posixpath_pure), false},
{"os", _Py_M__os, (int)sizeof(_Py_M__os), false},
{"site", _Py_M__site, (int)sizeof(_Py_M__site), false},
{"stat", _Py_M__stat, (int)sizeof(_Py_M__stat), false},
Expand Down Expand Up @@ -116,7 +121,8 @@ const struct _frozen *_PyImport_FrozenTest = test_modules;
static const struct _module_alias aliases[] = {
{"_frozen_importlib", "importlib._bootstrap"},
{"_frozen_importlib_external", "importlib._bootstrap_external"},
{"os.path", "posixpath"},
{"os.path", "<posixpath"},
{"os.path.pure", "posixpath.pure"},
{"__hello_alias__", "__hello__"},
{"__phello_alias__", "__hello__"},
{"__phello_alias__.spam", "__hello__"},
Expand Down
13 changes: 8 additions & 5 deletions Tools/build/freeze_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,14 @@
'_collections_abc',
'_sitebuiltins',
'genericpath',
'ntpath',
'posixpath',
# We must explicitly mark os.path as a frozen module
# even though it will never be imported.
f'{OS_PATH} : os.path',
'<ntpath>',
'ntpath.pure',
'<posixpath>',
'posixpath.pure',
# We must explicitly mark os.path and os.path.pure as frozen modules
# even though they will never be imported.
f'<{OS_PATH}> : os.path',
f'{OS_PATH}.pure : os.path.pure',
'os',
'site',
'stat',
Expand Down
Loading