MCPcopy Create free account
hub / github.com/tox-dev/filelock / FileLockMeta

Class FileLockMeta

src/filelock/_api.py:340–468  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

338
339
340class FileLockMeta(ABCMeta):
341 _instances: WeakValueDictionary[str, BaseFileLock]
342 _instances_lock: RLock
343 _instances_under_construction: set[str]
344
345 def __call__( # ruff:ignore[too-many-arguments] # forwards the public constructor's documented parameters
346 cls: type[_T],
347 lock_file: str | os.PathLike[str],
348 timeout: float = -1,
349 mode: int = _UNSET_FILE_MODE,
350 thread_local: bool = True, # ruff:ignore[boolean-type-hint-positional-argument, boolean-default-value-positional-argument] # public API: positional bool kept for backwards compatibility
351 *,
352 blocking: bool = True,
353 is_singleton: bool = False,
354 poll_interval: float = 0.05,
355 lifetime: float | None = None,
356 context_error_policy: ContextErrorPolicy = "chain",
357 close_error_policy: CloseErrorPolicy = "default",
358 fallback_to_soft: bool = True,
359 preserve_lock_file: bool = False,
360 on_acquired: Callable[[int], None] | None = None,
361 **kwargs: _ExtraValue,
362 ) -> _T:
363 _ensure_current_process()
364 lifetime = _resolve_lifetime(lifetime, cls, stacklevel=cls._constructor_lifetime_warning_stacklevel)
365 # Validate before building the instance: a raise inside __init__ would leave a half-constructed object whose
366 # __del__ then trips over the missing context.
367 context_error_policy = _resolve_context_error_policy(context_error_policy)
368 close_error_policy = _resolve_close_error_policy(close_error_policy)
369 preserve_lock_file = _resolve_preserve_lock_file(
370 preserve=preserve_lock_file, supported=cls._preserve_lock_file_supported, cls_name=cls.__name__
371 )
372 on_acquired = _resolve_on_acquired(on_acquired, supported=cls._on_acquired_supported, cls_name=cls.__name__)
373 params: dict[str, _LockInitValue | _ExtraValue] = {
374 "timeout": timeout,
375 "mode": mode,
376 "thread_local": thread_local,
377 "blocking": blocking,
378 "is_singleton": is_singleton,
379 "poll_interval": poll_interval,
380 "lifetime": lifetime,
381 "context_error_policy": context_error_policy,
382 "close_error_policy": close_error_policy,
383 "fallback_to_soft": fallback_to_soft,
384 "preserve_lock_file": preserve_lock_file,
385 "on_acquired": on_acquired,
386 **kwargs,
387 }
388 if not is_singleton:
389 return cls._create_instance(lock_file, params)
390
391 # Look up, build and store under one lock. Without it two threads racing the first construction for a
392 # path both miss the cache and each build their own instance, so callers relying on is_singleton for
393 # reentrant locking across instances end up with two "singletons" and acquire()'s deadlock check then
394 # rejects a legitimate reentrant acquire; the unguarded writes to the WeakValueDictionary are a data
395 # race besides. ReadWriteLock and SoftReadWriteLock already guard their singleton caches this way.
396 # Key the cache on the canonical form so equivalent spellings of one path share a singleton, and it matches the
397 # deadlock-registry key acquire() uses.

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected