Cat Feeder  1.0.0
The Cat feeder project
Loading...
Searching...
No Matches
final_singleton_class.py
Go to the documentation of this file.
1r"""
2# +==== BEGIN CatFeeder =================+
3# LOGO:
4# ..............(..../\
5# ...............)..(.')
6# ..............(../..)
7# ...............\‍(__)|
8# Inspired by Joan Stark
9# source https://www.asciiart.eu/
10# animals/cats
11# /STOP
12# PROJECT: CatFeeder
13# FILE: final_singleton_class.py
14# CREATION DATE: 22-11-2025
15# LAST Modified: 14:43:3 19-12-2025
16# DESCRIPTION:
17# This is the backend server in charge of making the actual website work.
18# /STOP
19# COPYRIGHT: (c) Cat Feeder
20# PURPOSE: The file containing the class in charge of acting as a shared instance that cannot contain other instanciated versions of the inheritor class.
21# // AR
22# +==== END CatFeeder =================+
23"""
24
25from __future__ import annotations
26
27import threading
28from typing import TypeVar
29try:
30 from typing import Self
31except ImportError:
32 from typing_extensions import Self
33
34T = TypeVar("T", bound="FinalSingleton")
35
36
38 """Protected-construction singleton base class.
39
40 Summary:
41 Subclass this to create a lazily-instantiated singleton whose *only*
42 instance must be created by a coordinating manager (e.g. ``RuntimeManager``).
43 Direct calls like ``MyService()`` raise ``RuntimeError``. This separates
44 lifecycle control from business logic while avoiding accidental multiple
45 instantiations under concurrency.
46
47 Construction Guard:
48 ``__new__`` checks the class-level flag ``_allow_create`` which the
49 manager toggles briefly. If the flag is not set, construction is refused.
50 This is lighter than a metaclass approach and keeps normal inheritance
51 semantics intact for subclasses.
52
53 Thread Safety:
54 A per-class ``_creation_lock`` is provided for managers wishing to guard
55 creation paths. The base itself does not acquire the lock; coordination
56 logic belongs in the manager to avoid hidden blocking inside ``__new__``.
57
58 Async Initialization:
59 Subclasses may define an ``async_init`` coroutine method. A manager can
60 detect and ``await`` it after creating the instance to perform async
61 setup (e.g. opening connections) without requiring an async ``__init__``.
62
63 Usage Example:
64 >>> class Config(FinalSingleton):
65 ... def __init__(self):
66 ... self.value = 42
67 >>> # WRONG (direct):
68 ... Config() # doctest: +IGNORE_EXCEPTION_DETAIL
69 Traceback (most recent call last):
70 RuntimeError: Config must be instantiated through RuntimeManager.get()
71 >>> # Manager (pseudo-code):
72 ... # RuntimeManager.get(Config) -> returns single instance
73
74 Design Notes:
75 - Keeps public API simple: subclass + retrieve via manager.
76 - Avoids global variables; instance access is centralized.
77 - Supports both sync and async init flows without coupling to event loop.
78
79 Limitations:
80 - Does not prevent manual flag flipping or reflection abuse; treat this
81 as a cooperative contract, not a security boundary.
82 - State reset/replacement must be explicitly handled by the manager if
83 ever required (e.g. test isolation).
84 """
85
86 # per-class lock to ensure only one instance is created, even under concurrency
87 _creation_lock = threading.Lock()
88
89 # flag preventing user-constructed instances
90 _allow_create: bool = False
91
92 def __new__(cls: type[Self], *_args, **_kwargs) -> Self:
93 if not cls._allow_create:
94 raise RuntimeError(
95 f"{cls.__name__} must be instantiated through RuntimeManager.get()"
96 )
97 return super().__new__(cls)