Skip to content

Commit 96881cd

Browse files
committed
Issue #27186: Add os.PathLike support to DirEntry
Initial patch thanks to Jelle Zijlstra.
1 parent 419e8ed commit 96881cd

4 files changed

Lines changed: 39 additions & 5 deletions

File tree

Doc/library/os.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1994,6 +1994,9 @@ features:
19941994
control over errors, you can catch :exc:`OSError` when calling one of the
19951995
``DirEntry`` methods and handle as appropriate.
19961996

1997+
To be directly usable as a path-like object, ``DirEntry`` implements the
1998+
:class:`os.PathLike` interface.
1999+
19972000
Attributes and methods on a ``DirEntry`` instance are as follows:
19982001

19992002
.. attribute:: name
@@ -2106,6 +2109,9 @@ features:
21062109

21072110
.. versionadded:: 3.5
21082111

2112+
.. versionchanged:: 3.6
2113+
Added support for the :class:`os.PathLike` interface.
2114+
21092115

21102116
.. function:: stat(path, \*, dir_fd=None, follow_symlinks=True)
21112117

Lib/test/test_os.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2824,11 +2824,13 @@ class TestScandir(unittest.TestCase):
28242824

28252825
def setUp(self):
28262826
self.path = os.path.realpath(support.TESTFN)
2827+
self.bytes_path = os.fsencode(self.path)
28272828
self.addCleanup(support.rmtree, self.path)
28282829
os.mkdir(self.path)
28292830

28302831
def create_file(self, name="file.txt"):
2831-
filename = os.path.join(self.path, name)
2832+
path = self.bytes_path if isinstance(name, bytes) else self.path
2833+
filename = os.path.join(path, name)
28322834
create_file(filename, b'python')
28332835
return filename
28342836

@@ -2917,15 +2919,16 @@ def test_attributes(self):
29172919
self.check_entry(entry, 'symlink_file.txt', False, True, True)
29182920

29192921
def get_entry(self, name):
2920-
entries = list(os.scandir(self.path))
2922+
path = self.bytes_path if isinstance(name, bytes) else self.path
2923+
entries = list(os.scandir(path))
29212924
self.assertEqual(len(entries), 1)
29222925

29232926
entry = entries[0]
29242927
self.assertEqual(entry.name, name)
29252928
return entry
29262929

2927-
def create_file_entry(self):
2928-
filename = self.create_file()
2930+
def create_file_entry(self, name='file.txt'):
2931+
filename = self.create_file(name=name)
29292932
return self.get_entry(os.path.basename(filename))
29302933

29312934
def test_current_directory(self):
@@ -2946,6 +2949,18 @@ def test_repr(self):
29462949
entry = self.create_file_entry()
29472950
self.assertEqual(repr(entry), "<DirEntry 'file.txt'>")
29482951

2952+
def test_fspath_protocol(self):
2953+
entry = self.create_file_entry()
2954+
self.assertEqual(os.fspath(entry), os.path.join(self.path, 'file.txt'))
2955+
2956+
def test_fspath_protocol_bytes(self):
2957+
bytes_filename = os.fsencode('bytesfile.txt')
2958+
bytes_entry = self.create_file_entry(name=bytes_filename)
2959+
fspath = os.fspath(bytes_entry)
2960+
self.assertIsInstance(fspath, bytes)
2961+
self.assertEqual(fspath,
2962+
os.path.join(os.fsencode(self.path),bytes_filename))
2963+
29492964
def test_removed_dir(self):
29502965
path = os.path.join(self.path, 'dir')
29512966

Misc/NEWS

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,14 @@ Core and Builtins
3838
Library
3939
-------
4040

41+
- Issue #27186: Add os.PathLike support to DirEntry (part of PEP 519).
42+
Initial patch by Jelle Zijlstra.
43+
4144
- Issue #20900: distutils register command now decodes HTTP responses
4245
correctly. Initial patch by ingrid.
4346

4447
- Issue #27186: Add os.PathLike support to pathlib, removing its provisional
45-
status (part of PEP 519).
48+
status (part of PEP 519). Initial patch by Dusty Phillips.
4649

4750
- Issue #27186: Add support for os.PathLike objects to os.fsencode() and
4851
os.fsdecode() (part of PEP 519).

Modules/posixmodule.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11718,6 +11718,13 @@ DirEntry_repr(DirEntry *self)
1171811718
return PyUnicode_FromFormat("<DirEntry %R>", self->name);
1171911719
}
1172011720

11721+
static PyObject *
11722+
DirEntry_fspath(DirEntry *self)
11723+
{
11724+
Py_INCREF(self->path);
11725+
return self->path;
11726+
}
11727+
1172111728
static PyMemberDef DirEntry_members[] = {
1172211729
{"name", T_OBJECT_EX, offsetof(DirEntry, name), READONLY,
1172311730
"the entry's base filename, relative to scandir() \"path\" argument"},
@@ -11742,6 +11749,9 @@ static PyMethodDef DirEntry_methods[] = {
1174211749
{"inode", (PyCFunction)DirEntry_inode, METH_NOARGS,
1174311750
"return inode of the entry; cached per entry",
1174411751
},
11752+
{"__fspath__", (PyCFunction)DirEntry_fspath, METH_NOARGS,
11753+
"returns the path for the entry",
11754+
},
1174511755
{NULL}
1174611756
};
1174711757

0 commit comments

Comments
 (0)