Skip to content

Commit b3dba18

Browse files
authored
GH-113528: Speed up pathlib ABC tests. (#113788)
- Add `__slots__` to dummy path classes. - Return namedtuple rather than `os.stat_result` from `DummyPath.stat()`. - Reduce maximum symlink count in `DummyPathWithSymlinks.resolve()`.
1 parent bc71ae2 commit b3dba18

File tree

2 files changed

+20
-6
lines changed

2 files changed

+20
-6
lines changed

Lib/pathlib/_abc.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010
# Internals
1111
#
1212

13-
# Maximum number of symlinks to follow in PathBase.resolve()
14-
_MAX_SYMLINKS = 40
15-
1613
# Reference for Windows paths can be found at
1714
# https://learn.microsoft.com/en-gb/windows/win32/fileio/naming-a-file .
1815
_WIN_RESERVED_NAMES = frozenset(
@@ -500,6 +497,9 @@ class PathBase(PurePathBase):
500497
"""
501498
__slots__ = ()
502499

500+
# Maximum number of symlinks to follow in resolve()
501+
_max_symlinks = 40
502+
503503
@classmethod
504504
def _unsupported(cls, method_name):
505505
msg = f"{cls.__name__}.{method_name}() is unsupported"
@@ -971,7 +971,7 @@ def resolve(self, strict=False):
971971
# Like Linux and macOS, raise OSError(errno.ELOOP) if too many symlinks are
972972
# encountered during resolution.
973973
link_count += 1
974-
if link_count >= _MAX_SYMLINKS:
974+
if link_count >= self._max_symlinks:
975975
raise OSError(ELOOP, "Too many symbolic links in path", str(self))
976976
target, target_parts = next_path.readlink()._split_stack()
977977
# If the symlink target is absolute (like '/etc/hosts'), set the current

Lib/test/test_pathlib/test_pathlib_abc.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import collections.abc
1+
import collections
22
import io
33
import os
44
import errno
@@ -43,6 +43,8 @@ def test_pathmod(self):
4343

4444

4545
class DummyPurePath(PurePathBase):
46+
__slots__ = ()
47+
4648
def __eq__(self, other):
4749
if not isinstance(other, DummyPurePath):
4850
return NotImplemented
@@ -660,11 +662,18 @@ def close(self):
660662
super().close()
661663

662664

665+
DummyPathStatResult = collections.namedtuple(
666+
'DummyPathStatResult',
667+
'st_mode st_ino st_dev st_nlink st_uid st_gid st_size st_atime st_mtime st_ctime')
668+
669+
663670
class DummyPath(PathBase):
664671
"""
665672
Simple implementation of PathBase that keeps files and directories in
666673
memory.
667674
"""
675+
__slots__ = ()
676+
668677
_files = {}
669678
_directories = {}
670679
_symlinks = {}
@@ -693,7 +702,7 @@ def stat(self, *, follow_symlinks=True):
693702
st_mode = stat.S_IFLNK
694703
else:
695704
raise FileNotFoundError(errno.ENOENT, "Not found", str(self))
696-
return os.stat_result((st_mode, hash(str(self)), 0, 0, 0, 0, 0, 0, 0, 0))
705+
return DummyPathStatResult(st_mode, hash(str(self)), 0, 0, 0, 0, 0, 0, 0, 0)
697706

698707
def open(self, mode='r', buffering=-1, encoding=None,
699708
errors=None, newline=None):
@@ -1728,6 +1737,11 @@ def test_walk_symlink_location(self):
17281737

17291738

17301739
class DummyPathWithSymlinks(DummyPath):
1740+
__slots__ = ()
1741+
1742+
# Reduce symlink traversal limit to make tests run faster.
1743+
_max_symlinks = 20
1744+
17311745
def readlink(self):
17321746
path = str(self.parent.resolve() / self.name)
17331747
if path in self._symlinks:

0 commit comments

Comments
 (0)