Skip to content

Commit 1672af6

Browse files
committed
Do not use weakrefs for fs objects in fake modules
- led to crashes of tests with manually created modules - weakrefs should only be used for backlinks
1 parent 5057955 commit 1672af6

8 files changed

Lines changed: 49 additions & 114 deletions

File tree

CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
The released versions correspond to PyPI releases.
33
`pyfakefs` versions follow [Semantic Versioning](https://semver.org/).
44

5+
## Unreleased
6+
7+
### Fixes
8+
* do not use weakrefs for filesystem objects in fake modules
9+
(see [#1284](https://github.com/pytest-dev/pyfakefs/issues/1284))
510

611
## [Version 6.1.1](https://pypi.python.org/pypi/pyfakefs/6.1.1) (2026-02-09)
712
Fixes a packaging issue in latest version.

pyfakefs/fake_filesystem_shutil.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import os
3535
import shutil
3636
import sys
37-
import weakref
3837
from threading import RLock
3938
from collections.abc import Callable
4039
from typing import TYPE_CHECKING
@@ -70,24 +69,16 @@ def dir():
7069
"""
7170
return ("disk_usage",)
7271

73-
def __init__(self, filesystem):
72+
def __init__(self, filesystem: FakeFilesystem):
7473
"""Construct fake shutil module using the fake filesystem.
7574
7675
Args:
7776
filesystem: FakeFilesystem used to provide file system information
7877
"""
79-
self._filesystem: weakref.ReferenceType[FakeFilesystem] = weakref.ref(
80-
filesystem
81-
)
78+
self.filesystem = filesystem
8279
self.shutil_module = shutil
8380
self._patch_level = 0
8481

85-
@property
86-
def filesystem(self) -> FakeFilesystem:
87-
fs = self._filesystem()
88-
assert fs is not None
89-
return fs
90-
9182
def _start_patching_global_vars(self):
9283
self._patch_level += 1
9384
if self._patch_level > 1:

pyfakefs/fake_io.py

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import _io # pytype: disable=import-error
2222
import io
2323
import sys
24-
import weakref
2524
from enum import Enum
2625
from typing import (
2726
Any,
@@ -71,18 +70,10 @@ def __init__(self, filesystem: FakeFilesystem):
7170
Args:
7271
filesystem: FakeFilesystem used to provide file system information.
7372
"""
74-
self._filesystem: weakref.ReferenceType[FakeFilesystem] = weakref.ref(
75-
filesystem
76-
)
73+
self.filesystem = filesystem
7774
self.skip_names: list[str] = []
7875
self._io_module = io
7976

80-
@property
81-
def filesystem(self) -> FakeFilesystem:
82-
fs = self._filesystem()
83-
assert fs is not None
84-
return fs
85-
8677
def open(
8778
self,
8879
file: AnyStr | int,
@@ -98,10 +89,8 @@ def open(
9889
"""Redirect the call to FakeFileOpen.
9990
See FakeFileOpen.call() for description.
10091
"""
101-
fs = self.filesystem
102-
assert fs is not None
10392
return fake_open(
104-
fs,
93+
self.filesystem,
10594
self.skip_names,
10695
file,
10796
mode,
@@ -170,9 +159,7 @@ def __init__(self, filesystem: FakeFilesystem):
170159
filesystem: FakeFilesystem used to provide file system
171160
information (currently not used).
172161
"""
173-
self.filesystem: weakref.ReferenceType[FakeFilesystem] = weakref.ref(
174-
filesystem
175-
)
162+
self.filesystem = filesystem
176163
self._fcntl_module = fcntl
177164

178165
def fcntl(self, fd: int, cmd: int, arg: int = 0) -> int | bytes:
@@ -193,7 +180,7 @@ def lockf(
193180

194181
def __getattribute__(self, name):
195182
"""Prevents patching of skipped modules."""
196-
fs: FakeFilesystem = object.__getattribute__(self, "filesystem")()
183+
fs: FakeFilesystem = object.__getattribute__(self, "filesystem")
197184
if fs.has_patcher:
198185
fnctl_module = object.__getattribute__(self, "_fcntl_module")
199186
if is_called_from_skipped_module(

pyfakefs/fake_open.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import io
2121
import os
2222
import sys
23-
import weakref
2423
from collections.abc import Callable
2524
from stat import (
2625
S_ISDIR,
@@ -129,18 +128,10 @@ def __init__(
129128
filesystem: FakeFilesystem used to provide file system information
130129
delete_on_close: optional boolean, deletes file on close()
131130
"""
132-
self._filesystem: weakref.ReferenceType[FakeFilesystem] = weakref.ref(
133-
filesystem
134-
)
131+
self.filesystem = filesystem
135132
self._delete_on_close = delete_on_close
136133
self.raw_io = raw_io
137134

138-
@property
139-
def filesystem(self) -> FakeFilesystem:
140-
fs = self._filesystem()
141-
assert fs is not None
142-
return fs
143-
144135
def __call__(self, *args: Any, **kwargs: Any) -> AnyFileWrapper:
145136
"""Redirects calls to file() or open() to appropriate method."""
146137
return self.call(*args, **kwargs)

pyfakefs/fake_os.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import os
2525
import sys
2626
import uuid
27-
import weakref
2827
from contextlib import contextmanager
2928
from stat import (
3029
S_IFREG,
@@ -154,22 +153,14 @@ def __init__(self, filesystem: FakeFilesystem):
154153
Args:
155154
filesystem: FakeFilesystem used to provide file system information
156155
"""
157-
self._filesystem: weakref.ReferenceType[FakeFilesystem] = weakref.ref(
158-
filesystem
159-
)
156+
self.filesystem = filesystem
160157
self.os_module: Any = os
161158
self.path = FakePathModule(filesystem, self)
162159
self._supports_follow_symlinks: set | None = None
163160
self._supports_dir_fd: set | None = None
164161
self._supports_effective_ids: set | None = None
165162
self._supports_fd: set | None = None
166163

167-
@property
168-
def filesystem(self) -> FakeFilesystem:
169-
fs = self._filesystem()
170-
assert fs is not None
171-
return fs
172-
173164
@property
174165
def devnull(self) -> str:
175166
return self.path.devnull

pyfakefs/fake_path.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import inspect
2222
import os
2323
import sys
24-
import weakref
2524
from stat import (
2625
S_IFDIR,
2726
S_IFMT,
@@ -113,19 +112,11 @@ def __init__(self, filesystem: FakeFilesystem, os_module: FakeOsModule):
113112
Args:
114113
filesystem: FakeFilesystem used to provide file system information
115114
"""
116-
self._filesystem: weakref.ReferenceType[FakeFilesystem] = weakref.ref(
117-
filesystem
118-
)
115+
self.filesystem = filesystem
119116
self._os_path = self._OS_PATH_COPY
120117
self._os_path.os = self.os = os_module # type: ignore[attr-defined]
121118
self.reset(filesystem)
122119

123-
@property
124-
def filesystem(self) -> FakeFilesystem:
125-
fs = self._filesystem()
126-
assert fs is not None
127-
return fs
128-
129120
@classmethod
130121
def reset(cls, filesystem: FakeFilesystem) -> None:
131122
cls.sep = filesystem.path_separator
@@ -540,17 +531,9 @@ def __init__(self, filesystem: FakeFilesystem):
540531
"""
541532
import nt # type:ignore[import]
542533

543-
self._filesystem: weakref.ReferenceType[FakeFilesystem] = weakref.ref(
544-
filesystem
545-
)
534+
self.filesystem = filesystem
546535
self.nt_module: Any = nt
547536

548-
@property
549-
def filesystem(self) -> FakeFilesystem:
550-
fs = self._filesystem()
551-
assert fs is not None
552-
return fs
553-
554537
def getcwd(self) -> str:
555538
"""Return current working directory."""
556539
return to_string(self.filesystem.cwd)

0 commit comments

Comments
 (0)