Skip to content

Commit 7071d88

Browse files
committed
Adapt fake pathlib to changes in Python 3.12a7
- stat.st_ctype is deprecated under Windows in 3.12 on, comment out the tests for the time being (support for st_birthdate to be added)
1 parent 36170ee commit 7071d88

File tree

3 files changed

+62
-50
lines changed

3 files changed

+62
-50
lines changed

CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ The released versions correspond to PyPI releases.
33

44
## Unreleased
55

6+
### Changes
7+
* Adapted fake pathlib to changes in Python 3.12a7 (last alpha version)
8+
69
### Fixes
710
* Properties defining the capabilities of some `os` functions like
811
`os.supports_follow_symlinks` are now properly faked to contain the fake functions

pyfakefs/fake_pathlib.py

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -520,39 +520,41 @@ def __new__(cls, *args, **kwargs):
520520
if cls.filesystem.is_windows_fs
521521
else FakePathlibModule.PosixPath
522522
)
523-
self = cls._from_parts(args)
524-
return self
525-
526-
@classmethod
527-
def _from_parts(cls, args, init=False): # pylint: disable=unused-argument
528-
# Overwritten to call _init to set the fake accessor,
529-
# which is not done since Python 3.10
530-
self = object.__new__(cls)
531-
self._init()
532-
parse_fct = (
533-
self._parse_parts if sys.version_info >= (3, 12) else self._parse_args
534-
)
535-
drv, root, parts = parse_fct(args)
536-
self._drv = drv
537-
self._root = root
538-
self._parts = parts
539-
return self
540-
541-
@classmethod
542-
def _from_parsed_parts(cls, drv, root, parts):
543-
# Overwritten to call _init to set the fake accessor,
544-
# which is not done since Python 3.10
545-
self = object.__new__(cls)
546-
self._init()
547-
self._drv = drv
548-
self._root = root
549-
self._parts = parts
550-
return self
551-
552-
def _init(self, template=None):
553-
"""Initializer called from base class."""
554-
self._accessor = _fake_accessor
555-
self._closed = False
523+
if sys.version_info < (3, 12):
524+
return cls._from_parts(args)
525+
else:
526+
return object.__new__(cls)
527+
528+
if sys.version_info[:2] == (3, 10):
529+
# Overwritten class methods to call _init to set the fake accessor,
530+
# which is not done in Python 3.10, and not needed from Python 3.11 on
531+
@classmethod
532+
def _from_parts(cls, args, init=False): # pylint: disable=unused-argument
533+
self = object.__new__(cls)
534+
self._init()
535+
drv, root, parts = self._parse_args(args)
536+
self._drv = drv
537+
self._root = root
538+
self._parts = parts
539+
return self
540+
541+
@classmethod
542+
def _from_parsed_parts(cls, drv, root, parts):
543+
self = object.__new__(cls)
544+
self._drv = drv
545+
self._root = root
546+
self._parts = parts
547+
self._init()
548+
return self
549+
550+
if sys.version_info < (3, 11):
551+
552+
def _init(self, template=None):
553+
"""Initializer called from base class."""
554+
# only needed until Python 3.10
555+
self._accessor = _fake_accessor
556+
# only needed until Python 3.8
557+
self._closed = False
556558

557559
def _path(self):
558560
"""Returns the underlying path string as used by the fake
@@ -591,8 +593,7 @@ def resolve(self, strict=None):
591593
"resolve() got an unexpected keyword argument 'strict'"
592594
)
593595
strict = True
594-
if self._closed:
595-
self._raise_closed()
596+
self._raise_on_closed()
596597
path = self._flavour.resolve(self, strict=strict)
597598
if path is None:
598599
self.stat()
@@ -607,8 +608,7 @@ def open(self, mode="r", buffering=-1, encoding=None, errors=None, newline=None)
607608
OSError: if the target object is a directory, the path is invalid
608609
or permission is denied.
609610
"""
610-
if self._closed:
611-
self._raise_closed()
611+
self._raise_on_closed()
612612
return FakeFileOpen(self.filesystem)(
613613
self._path(), mode, buffering, encoding, errors, newline
614614
)
@@ -720,6 +720,10 @@ def expanduser(self):
720720
)
721721
)
722722

723+
def _raise_on_closed(self):
724+
if sys.version_info < (3, 9) and self._closed:
725+
self._raise_closed()
726+
723727
def touch(self, mode=0o666, exist_ok=True):
724728
"""Create a fake file for the path with the given access mode,
725729
if it doesn't exist.
@@ -732,8 +736,7 @@ def touch(self, mode=0o666, exist_ok=True):
732736
Raises:
733737
FileExistsError: if the file exists and exits_ok is False.
734738
"""
735-
if self._closed:
736-
self._raise_closed()
739+
self._raise_on_closed()
737740
if self.exists():
738741
if exist_ok:
739742
self.filesystem.utime(self._path(), times=None)
@@ -751,7 +754,7 @@ def touch(self, mode=0o666, exist_ok=True):
751754

752755
def is_absolute(self):
753756
if self.filesystem.is_windows_fs:
754-
return self._drv and self._root
757+
return self.drive and self.root
755758
return os.path.isabs(self._path())
756759

757760
def is_reserved(self):
@@ -887,8 +890,10 @@ def __new__(cls, *args, **kwargs):
887890
if os.name == "nt"
888891
else RealPathlibModule.PosixPath
889892
)
890-
self = cls._from_parts(args)
891-
return self
893+
if sys.version_info < (3, 12):
894+
return cls._from_parts(args)
895+
else:
896+
return object.__new__(cls)
892897

893898

894899
if sys.version_info > (3, 10):

pyfakefs/tests/fake_os_test.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5200,10 +5200,12 @@ def check_stat(
52005200
self, absolute_symlink_expected_size, relative_symlink_expected_size
52015201
):
52025202
self.assertEqual(self.FILE_SIZE, self.dir_entries[1].stat().st_size)
5203-
self.assertEqual(
5204-
int(self.os.stat(self.dir_path).st_ctime),
5205-
int(self.dir_entries[0].stat().st_ctime),
5206-
)
5203+
if not self.is_windows_fs or sys.version_info < (3, 12):
5204+
# behavior of st_ctime changed in 3.12, to be adapted later
5205+
self.assertEqual(
5206+
int(self.os.stat(self.dir_path).st_ctime),
5207+
int(self.dir_entries[0].stat().st_ctime),
5208+
)
52075209

52085210
if self.supports_symlinks:
52095211
self.assertEqual(self.LINKED_FILE_SIZE, self.dir_entries[3].stat().st_size)
@@ -5234,10 +5236,12 @@ def test_stat_windows(self):
52345236
self.check_stat(0, 0)
52355237

52365238
def test_index_access_to_stat_times_returns_int(self):
5237-
self.assertEqual(
5238-
self.os.stat(self.dir_path)[stat.ST_CTIME],
5239-
int(self.dir_entries[0].stat().st_ctime),
5240-
)
5239+
if not self.is_windows_fs or sys.version_info < (3, 12):
5240+
# behavior of st_ctime changed in 3.12, to be adapted later
5241+
self.assertEqual(
5242+
self.os.stat(self.dir_path)[stat.ST_CTIME],
5243+
int(self.dir_entries[0].stat().st_ctime),
5244+
)
52415245
if self.supports_symlinks:
52425246
self.assertEqual(
52435247
self.os.stat(self.linked_dir_path)[stat.ST_MTIME],

0 commit comments

Comments
 (0)