Skip to content

Commit c64787f

Browse files
authored
Don't initialize BaseFileLock when just returning existing instance (#334)
1 parent 87453f3 commit c64787f

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

src/filelock/_api.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,28 +80,33 @@ class ThreadLocalFileContext(FileLockContext, local):
8080
class BaseFileLock(ABC, contextlib.ContextDecorator):
8181
"""Abstract base class for a file lock object."""
8282

83-
_instances: WeakValueDictionary[str, BaseFileLock]
83+
_instances: WeakValueDictionary[str, Self]
8484

8585
def __new__( # noqa: PLR0913
8686
cls,
8787
lock_file: str | os.PathLike[str],
8888
timeout: float = -1,
8989
mode: int = 0o644,
90-
thread_local: bool = True, # noqa: ARG003, FBT001, FBT002
90+
thread_local: bool = True, # noqa: FBT001, FBT002
9191
*,
92-
blocking: bool = True, # noqa: ARG003
92+
blocking: bool = True,
9393
is_singleton: bool = False,
9494
**kwargs: Any, # capture remaining kwargs for subclasses # noqa: ARG003, ANN401
9595
) -> Self:
9696
"""Create a new lock object or if specified return the singleton instance for the lock file."""
9797
if not is_singleton:
98-
return super().__new__(cls)
98+
self = super().__new__(cls)
99+
self._initialize(lock_file, timeout, mode, thread_local, blocking=blocking, is_singleton=is_singleton)
100+
return self
99101

100102
instance = cls._instances.get(str(lock_file))
101103
if not instance:
102-
instance = super().__new__(cls)
103-
cls._instances[str(lock_file)] = instance
104-
elif timeout != instance.timeout or mode != instance.mode:
104+
self = super().__new__(cls)
105+
self._initialize(lock_file, timeout, mode, thread_local, blocking=blocking, is_singleton=is_singleton)
106+
cls._instances[str(lock_file)] = self
107+
return self
108+
109+
if timeout != instance.timeout or mode != instance.mode:
105110
msg = "Singleton lock instances cannot be initialized with differing arguments"
106111
raise ValueError(msg)
107112

@@ -112,7 +117,7 @@ def __init_subclass__(cls, **kwargs: dict[str, Any]) -> None:
112117
super().__init_subclass__(**kwargs)
113118
cls._instances = WeakValueDictionary()
114119

115-
def __init__( # noqa: PLR0913
120+
def _initialize( # noqa: PLR0913
116121
self,
117122
lock_file: str | os.PathLike[str],
118123
timeout: float = -1,

tests/test_filelock.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,23 @@ def test_nested_forced_release(lock_type: type[BaseFileLock], tmp_path: Path) ->
201201
assert not lock.is_locked
202202

203203

204+
@pytest.mark.parametrize("lock_type", [FileLock, SoftFileLock])
205+
def test_nested_contruct(lock_type: type[BaseFileLock], tmp_path: Path) -> None:
206+
# lock is re-entrant for a given file even if it is constructed multiple times
207+
lock_path = tmp_path / "a"
208+
209+
with lock_type(str(lock_path), is_singleton=True, timeout=2) as lock_1:
210+
assert lock_1.is_locked
211+
212+
with lock_type(str(lock_path), is_singleton=True, timeout=2) as lock_2:
213+
assert lock_2 is lock_1
214+
assert lock_2.is_locked
215+
216+
assert lock_1.is_locked
217+
218+
assert not lock_1.is_locked
219+
220+
204221
_ExcInfoType = Union[Tuple[Type[BaseException], BaseException, TracebackType], Tuple[None, None, None]]
205222

206223

0 commit comments

Comments
 (0)