mirror of
				https://forge.chapril.org/tykayn/book_generator
				synced 2025-06-20 01:34:43 +02:00 
			
		
		
		
	⚡ - sauvegarde automatique de l'avancement du livre
This commit is contained in:
		
							parent
							
								
									de532abbb7
								
							
						
					
					
						commit
						375fbb3a7a
					
				
					 1814 changed files with 334236 additions and 0 deletions
				
			
		
							
								
								
									
										17
									
								
								venv/lib/python3.11/site-packages/blinker/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								venv/lib/python3.11/site-packages/blinker/__init__.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,17 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| from .base import ANY | ||||
| from .base import default_namespace | ||||
| from .base import NamedSignal | ||||
| from .base import Namespace | ||||
| from .base import Signal | ||||
| from .base import signal | ||||
| 
 | ||||
| __all__ = [ | ||||
|     "ANY", | ||||
|     "default_namespace", | ||||
|     "NamedSignal", | ||||
|     "Namespace", | ||||
|     "Signal", | ||||
|     "signal", | ||||
| ] | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										64
									
								
								venv/lib/python3.11/site-packages/blinker/_utilities.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								venv/lib/python3.11/site-packages/blinker/_utilities.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,64 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| import collections.abc as c | ||||
| import inspect | ||||
| import typing as t | ||||
| from weakref import ref | ||||
| from weakref import WeakMethod | ||||
| 
 | ||||
| T = t.TypeVar("T") | ||||
| 
 | ||||
| 
 | ||||
| class Symbol: | ||||
|     """A constant symbol, nicer than ``object()``. Repeated calls return the | ||||
|     same instance. | ||||
| 
 | ||||
|     >>> Symbol('foo') is Symbol('foo') | ||||
|     True | ||||
|     >>> Symbol('foo') | ||||
|     foo | ||||
|     """ | ||||
| 
 | ||||
|     symbols: t.ClassVar[dict[str, Symbol]] = {} | ||||
| 
 | ||||
|     def __new__(cls, name: str) -> Symbol: | ||||
|         if name in cls.symbols: | ||||
|             return cls.symbols[name] | ||||
| 
 | ||||
|         obj = super().__new__(cls) | ||||
|         cls.symbols[name] = obj | ||||
|         return obj | ||||
| 
 | ||||
|     def __init__(self, name: str) -> None: | ||||
|         self.name = name | ||||
| 
 | ||||
|     def __repr__(self) -> str: | ||||
|         return self.name | ||||
| 
 | ||||
|     def __getnewargs__(self) -> tuple[t.Any, ...]: | ||||
|         return (self.name,) | ||||
| 
 | ||||
| 
 | ||||
| def make_id(obj: object) -> c.Hashable: | ||||
|     """Get a stable identifier for a receiver or sender, to be used as a dict | ||||
|     key or in a set. | ||||
|     """ | ||||
|     if inspect.ismethod(obj): | ||||
|         # The id of a bound method is not stable, but the id of the unbound | ||||
|         # function and instance are. | ||||
|         return id(obj.__func__), id(obj.__self__) | ||||
| 
 | ||||
|     if isinstance(obj, (str, int)): | ||||
|         # Instances with the same value always compare equal and have the same | ||||
|         # hash, even if the id may change. | ||||
|         return obj | ||||
| 
 | ||||
|     # Assume other types are not hashable but will always be the same instance. | ||||
|     return id(obj) | ||||
| 
 | ||||
| 
 | ||||
| def make_ref(obj: T, callback: c.Callable[[ref[T]], None] | None = None) -> ref[T]: | ||||
|     if inspect.ismethod(obj): | ||||
|         return WeakMethod(obj, callback)  # type: ignore[arg-type, return-value] | ||||
| 
 | ||||
|     return ref(obj, callback) | ||||
							
								
								
									
										512
									
								
								venv/lib/python3.11/site-packages/blinker/base.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										512
									
								
								venv/lib/python3.11/site-packages/blinker/base.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,512 @@ | |||
| from __future__ import annotations | ||||
| 
 | ||||
| import collections.abc as c | ||||
| import sys | ||||
| import typing as t | ||||
| import weakref | ||||
| from collections import defaultdict | ||||
| from contextlib import contextmanager | ||||
| from functools import cached_property | ||||
| from inspect import iscoroutinefunction | ||||
| 
 | ||||
| from ._utilities import make_id | ||||
| from ._utilities import make_ref | ||||
| from ._utilities import Symbol | ||||
| 
 | ||||
| F = t.TypeVar("F", bound=c.Callable[..., t.Any]) | ||||
| 
 | ||||
| ANY = Symbol("ANY") | ||||
| """Symbol for "any sender".""" | ||||
| 
 | ||||
| ANY_ID = 0 | ||||
| 
 | ||||
| 
 | ||||
| class Signal: | ||||
|     """A notification emitter. | ||||
| 
 | ||||
|     :param doc: The docstring for the signal. | ||||
|     """ | ||||
| 
 | ||||
|     ANY = ANY | ||||
|     """An alias for the :data:`~blinker.ANY` sender symbol.""" | ||||
| 
 | ||||
|     set_class: type[set[t.Any]] = set | ||||
|     """The set class to use for tracking connected receivers and senders. | ||||
|     Python's ``set`` is unordered. If receivers must be dispatched in the order | ||||
|     they were connected, an ordered set implementation can be used. | ||||
| 
 | ||||
|     .. versionadded:: 1.7 | ||||
|     """ | ||||
| 
 | ||||
|     @cached_property | ||||
|     def receiver_connected(self) -> Signal: | ||||
|         """Emitted at the end of each :meth:`connect` call. | ||||
| 
 | ||||
|         The signal sender is the signal instance, and the :meth:`connect` | ||||
|         arguments are passed through: ``receiver``, ``sender``, and ``weak``. | ||||
| 
 | ||||
|         .. versionadded:: 1.2 | ||||
|         """ | ||||
|         return Signal(doc="Emitted after a receiver connects.") | ||||
| 
 | ||||
|     @cached_property | ||||
|     def receiver_disconnected(self) -> Signal: | ||||
|         """Emitted at the end of each :meth:`disconnect` call. | ||||
| 
 | ||||
|         The sender is the signal instance, and the :meth:`disconnect` arguments | ||||
|         are passed through: ``receiver`` and ``sender``. | ||||
| 
 | ||||
|         This signal is emitted **only** when :meth:`disconnect` is called | ||||
|         explicitly. This signal cannot be emitted by an automatic disconnect | ||||
|         when a weakly referenced receiver or sender goes out of scope, as the | ||||
|         instance is no longer be available to be used as the sender for this | ||||
|         signal. | ||||
| 
 | ||||
|         An alternative approach is available by subscribing to | ||||
|         :attr:`receiver_connected` and setting up a custom weakref cleanup | ||||
|         callback on weak receivers and senders. | ||||
| 
 | ||||
|         .. versionadded:: 1.2 | ||||
|         """ | ||||
|         return Signal(doc="Emitted after a receiver disconnects.") | ||||
| 
 | ||||
|     def __init__(self, doc: str | None = None) -> None: | ||||
|         if doc: | ||||
|             self.__doc__ = doc | ||||
| 
 | ||||
|         self.receivers: dict[ | ||||
|             t.Any, weakref.ref[c.Callable[..., t.Any]] | c.Callable[..., t.Any] | ||||
|         ] = {} | ||||
|         """The map of connected receivers. Useful to quickly check if any | ||||
|         receivers are connected to the signal: ``if s.receivers:``. The | ||||
|         structure and data is not part of the public API, but checking its | ||||
|         boolean value is. | ||||
|         """ | ||||
| 
 | ||||
|         self.is_muted: bool = False | ||||
|         self._by_receiver: dict[t.Any, set[t.Any]] = defaultdict(self.set_class) | ||||
|         self._by_sender: dict[t.Any, set[t.Any]] = defaultdict(self.set_class) | ||||
|         self._weak_senders: dict[t.Any, weakref.ref[t.Any]] = {} | ||||
| 
 | ||||
|     def connect(self, receiver: F, sender: t.Any = ANY, weak: bool = True) -> F: | ||||
|         """Connect ``receiver`` to be called when the signal is sent by | ||||
|         ``sender``. | ||||
| 
 | ||||
|         :param receiver: The callable to call when :meth:`send` is called with | ||||
|             the given ``sender``, passing ``sender`` as a positional argument | ||||
|             along with any extra keyword arguments. | ||||
|         :param sender: Any object or :data:`ANY`. ``receiver`` will only be | ||||
|             called when :meth:`send` is called with this sender. If ``ANY``, the | ||||
|             receiver will be called for any sender. A receiver may be connected | ||||
|             to multiple senders by calling :meth:`connect` multiple times. | ||||
|         :param weak: Track the receiver with a :mod:`weakref`. The receiver will | ||||
|             be automatically disconnected when it is garbage collected. When | ||||
|             connecting a receiver defined within a function, set to ``False``, | ||||
|             otherwise it will be disconnected when the function scope ends. | ||||
|         """ | ||||
|         receiver_id = make_id(receiver) | ||||
|         sender_id = ANY_ID if sender is ANY else make_id(sender) | ||||
| 
 | ||||
|         if weak: | ||||
|             self.receivers[receiver_id] = make_ref( | ||||
|                 receiver, self._make_cleanup_receiver(receiver_id) | ||||
|             ) | ||||
|         else: | ||||
|             self.receivers[receiver_id] = receiver | ||||
| 
 | ||||
|         self._by_sender[sender_id].add(receiver_id) | ||||
|         self._by_receiver[receiver_id].add(sender_id) | ||||
| 
 | ||||
|         if sender is not ANY and sender_id not in self._weak_senders: | ||||
|             # store a cleanup for weakref-able senders | ||||
|             try: | ||||
|                 self._weak_senders[sender_id] = make_ref( | ||||
|                     sender, self._make_cleanup_sender(sender_id) | ||||
|                 ) | ||||
|             except TypeError: | ||||
|                 pass | ||||
| 
 | ||||
|         if "receiver_connected" in self.__dict__ and self.receiver_connected.receivers: | ||||
|             try: | ||||
|                 self.receiver_connected.send( | ||||
|                     self, receiver=receiver, sender=sender, weak=weak | ||||
|                 ) | ||||
|             except TypeError: | ||||
|                 # TODO no explanation or test for this | ||||
|                 self.disconnect(receiver, sender) | ||||
|                 raise | ||||
| 
 | ||||
|         return receiver | ||||
| 
 | ||||
|     def connect_via(self, sender: t.Any, weak: bool = False) -> c.Callable[[F], F]: | ||||
|         """Connect the decorated function to be called when the signal is sent | ||||
|         by ``sender``. | ||||
| 
 | ||||
|         The decorated function will be called when :meth:`send` is called with | ||||
|         the given ``sender``, passing ``sender`` as a positional argument along | ||||
|         with any extra keyword arguments. | ||||
| 
 | ||||
|         :param sender: Any object or :data:`ANY`. ``receiver`` will only be | ||||
|             called when :meth:`send` is called with this sender. If ``ANY``, the | ||||
|             receiver will be called for any sender. A receiver may be connected | ||||
|             to multiple senders by calling :meth:`connect` multiple times. | ||||
|         :param weak: Track the receiver with a :mod:`weakref`. The receiver will | ||||
|             be automatically disconnected when it is garbage collected. When | ||||
|             connecting a receiver defined within a function, set to ``False``, | ||||
|             otherwise it will be disconnected when the function scope ends.= | ||||
| 
 | ||||
|         .. versionadded:: 1.1 | ||||
|         """ | ||||
| 
 | ||||
|         def decorator(fn: F) -> F: | ||||
|             self.connect(fn, sender, weak) | ||||
|             return fn | ||||
| 
 | ||||
|         return decorator | ||||
| 
 | ||||
|     @contextmanager | ||||
|     def connected_to( | ||||
|         self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY | ||||
|     ) -> c.Generator[None, None, None]: | ||||
|         """A context manager that temporarily connects ``receiver`` to the | ||||
|         signal while a ``with`` block executes. When the block exits, the | ||||
|         receiver is disconnected. Useful for tests. | ||||
| 
 | ||||
|         :param receiver: The callable to call when :meth:`send` is called with | ||||
|             the given ``sender``, passing ``sender`` as a positional argument | ||||
|             along with any extra keyword arguments. | ||||
|         :param sender: Any object or :data:`ANY`. ``receiver`` will only be | ||||
|             called when :meth:`send` is called with this sender. If ``ANY``, the | ||||
|             receiver will be called for any sender. | ||||
| 
 | ||||
|         .. versionadded:: 1.1 | ||||
|         """ | ||||
|         self.connect(receiver, sender=sender, weak=False) | ||||
| 
 | ||||
|         try: | ||||
|             yield None | ||||
|         finally: | ||||
|             self.disconnect(receiver) | ||||
| 
 | ||||
|     @contextmanager | ||||
|     def muted(self) -> c.Generator[None, None, None]: | ||||
|         """A context manager that temporarily disables the signal. No receivers | ||||
|         will be called if the signal is sent, until the ``with`` block exits. | ||||
|         Useful for tests. | ||||
|         """ | ||||
|         self.is_muted = True | ||||
| 
 | ||||
|         try: | ||||
|             yield None | ||||
|         finally: | ||||
|             self.is_muted = False | ||||
| 
 | ||||
|     def send( | ||||
|         self, | ||||
|         sender: t.Any | None = None, | ||||
|         /, | ||||
|         *, | ||||
|         _async_wrapper: c.Callable[ | ||||
|             [c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]]], c.Callable[..., t.Any] | ||||
|         ] | ||||
|         | None = None, | ||||
|         **kwargs: t.Any, | ||||
|     ) -> list[tuple[c.Callable[..., t.Any], t.Any]]: | ||||
|         """Call all receivers that are connected to the given ``sender`` | ||||
|         or :data:`ANY`. Each receiver is called with ``sender`` as a positional | ||||
|         argument along with any extra keyword arguments. Return a list of | ||||
|         ``(receiver, return value)`` tuples. | ||||
| 
 | ||||
|         The order receivers are called is undefined, but can be influenced by | ||||
|         setting :attr:`set_class`. | ||||
| 
 | ||||
|         If a receiver raises an exception, that exception will propagate up. | ||||
|         This makes debugging straightforward, with an assumption that correctly | ||||
|         implemented receivers will not raise. | ||||
| 
 | ||||
|         :param sender: Call receivers connected to this sender, in addition to | ||||
|             those connected to :data:`ANY`. | ||||
|         :param _async_wrapper: Will be called on any receivers that are async | ||||
|             coroutines to turn them into sync callables. For example, could run | ||||
|             the receiver with an event loop. | ||||
|         :param kwargs: Extra keyword arguments to pass to each receiver. | ||||
| 
 | ||||
|         .. versionchanged:: 1.7 | ||||
|             Added the ``_async_wrapper`` argument. | ||||
|         """ | ||||
|         if self.is_muted: | ||||
|             return [] | ||||
| 
 | ||||
|         results = [] | ||||
| 
 | ||||
|         for receiver in self.receivers_for(sender): | ||||
|             if iscoroutinefunction(receiver): | ||||
|                 if _async_wrapper is None: | ||||
|                     raise RuntimeError("Cannot send to a coroutine function.") | ||||
| 
 | ||||
|                 result = _async_wrapper(receiver)(sender, **kwargs) | ||||
|             else: | ||||
|                 result = receiver(sender, **kwargs) | ||||
| 
 | ||||
|             results.append((receiver, result)) | ||||
| 
 | ||||
|         return results | ||||
| 
 | ||||
|     async def send_async( | ||||
|         self, | ||||
|         sender: t.Any | None = None, | ||||
|         /, | ||||
|         *, | ||||
|         _sync_wrapper: c.Callable[ | ||||
|             [c.Callable[..., t.Any]], c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]] | ||||
|         ] | ||||
|         | None = None, | ||||
|         **kwargs: t.Any, | ||||
|     ) -> list[tuple[c.Callable[..., t.Any], t.Any]]: | ||||
|         """Await all receivers that are connected to the given ``sender`` | ||||
|         or :data:`ANY`. Each receiver is called with ``sender`` as a positional | ||||
|         argument along with any extra keyword arguments. Return a list of | ||||
|         ``(receiver, return value)`` tuples. | ||||
| 
 | ||||
|         The order receivers are called is undefined, but can be influenced by | ||||
|         setting :attr:`set_class`. | ||||
| 
 | ||||
|         If a receiver raises an exception, that exception will propagate up. | ||||
|         This makes debugging straightforward, with an assumption that correctly | ||||
|         implemented receivers will not raise. | ||||
| 
 | ||||
|         :param sender: Call receivers connected to this sender, in addition to | ||||
|             those connected to :data:`ANY`. | ||||
|         :param _sync_wrapper: Will be called on any receivers that are sync | ||||
|             callables to turn them into async coroutines. For example, | ||||
|             could call the receiver in a thread. | ||||
|         :param kwargs: Extra keyword arguments to pass to each receiver. | ||||
| 
 | ||||
|         .. versionadded:: 1.7 | ||||
|         """ | ||||
|         if self.is_muted: | ||||
|             return [] | ||||
| 
 | ||||
|         results = [] | ||||
| 
 | ||||
|         for receiver in self.receivers_for(sender): | ||||
|             if not iscoroutinefunction(receiver): | ||||
|                 if _sync_wrapper is None: | ||||
|                     raise RuntimeError("Cannot send to a non-coroutine function.") | ||||
| 
 | ||||
|                 result = await _sync_wrapper(receiver)(sender, **kwargs) | ||||
|             else: | ||||
|                 result = await receiver(sender, **kwargs) | ||||
| 
 | ||||
|             results.append((receiver, result)) | ||||
| 
 | ||||
|         return results | ||||
| 
 | ||||
|     def has_receivers_for(self, sender: t.Any) -> bool: | ||||
|         """Check if there is at least one receiver that will be called with the | ||||
|         given ``sender``. A receiver connected to :data:`ANY` will always be | ||||
|         called, regardless of sender. Does not check if weakly referenced | ||||
|         receivers are still live. See :meth:`receivers_for` for a stronger | ||||
|         search. | ||||
| 
 | ||||
|         :param sender: Check for receivers connected to this sender, in addition | ||||
|             to those connected to :data:`ANY`. | ||||
|         """ | ||||
|         if not self.receivers: | ||||
|             return False | ||||
| 
 | ||||
|         if self._by_sender[ANY_ID]: | ||||
|             return True | ||||
| 
 | ||||
|         if sender is ANY: | ||||
|             return False | ||||
| 
 | ||||
|         return make_id(sender) in self._by_sender | ||||
| 
 | ||||
|     def receivers_for( | ||||
|         self, sender: t.Any | ||||
|     ) -> c.Generator[c.Callable[..., t.Any], None, None]: | ||||
|         """Yield each receiver to be called for ``sender``, in addition to those | ||||
|         to be called for :data:`ANY`. Weakly referenced receivers that are not | ||||
|         live will be disconnected and skipped. | ||||
| 
 | ||||
|         :param sender: Yield receivers connected to this sender, in addition | ||||
|             to those connected to :data:`ANY`. | ||||
|         """ | ||||
|         # TODO: test receivers_for(ANY) | ||||
|         if not self.receivers: | ||||
|             return | ||||
| 
 | ||||
|         sender_id = make_id(sender) | ||||
| 
 | ||||
|         if sender_id in self._by_sender: | ||||
|             ids = self._by_sender[ANY_ID] | self._by_sender[sender_id] | ||||
|         else: | ||||
|             ids = self._by_sender[ANY_ID].copy() | ||||
| 
 | ||||
|         for receiver_id in ids: | ||||
|             receiver = self.receivers.get(receiver_id) | ||||
| 
 | ||||
|             if receiver is None: | ||||
|                 continue | ||||
| 
 | ||||
|             if isinstance(receiver, weakref.ref): | ||||
|                 strong = receiver() | ||||
| 
 | ||||
|                 if strong is None: | ||||
|                     self._disconnect(receiver_id, ANY_ID) | ||||
|                     continue | ||||
| 
 | ||||
|                 yield strong | ||||
|             else: | ||||
|                 yield receiver | ||||
| 
 | ||||
|     def disconnect(self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY) -> None: | ||||
|         """Disconnect ``receiver`` from being called when the signal is sent by | ||||
|         ``sender``. | ||||
| 
 | ||||
|         :param receiver: A connected receiver callable. | ||||
|         :param sender: Disconnect from only this sender. By default, disconnect | ||||
|             from all senders. | ||||
|         """ | ||||
|         sender_id: c.Hashable | ||||
| 
 | ||||
|         if sender is ANY: | ||||
|             sender_id = ANY_ID | ||||
|         else: | ||||
|             sender_id = make_id(sender) | ||||
| 
 | ||||
|         receiver_id = make_id(receiver) | ||||
|         self._disconnect(receiver_id, sender_id) | ||||
| 
 | ||||
|         if ( | ||||
|             "receiver_disconnected" in self.__dict__ | ||||
|             and self.receiver_disconnected.receivers | ||||
|         ): | ||||
|             self.receiver_disconnected.send(self, receiver=receiver, sender=sender) | ||||
| 
 | ||||
|     def _disconnect(self, receiver_id: c.Hashable, sender_id: c.Hashable) -> None: | ||||
|         if sender_id == ANY_ID: | ||||
|             if self._by_receiver.pop(receiver_id, None) is not None: | ||||
|                 for bucket in self._by_sender.values(): | ||||
|                     bucket.discard(receiver_id) | ||||
| 
 | ||||
|             self.receivers.pop(receiver_id, None) | ||||
|         else: | ||||
|             self._by_sender[sender_id].discard(receiver_id) | ||||
|             self._by_receiver[receiver_id].discard(sender_id) | ||||
| 
 | ||||
|     def _make_cleanup_receiver( | ||||
|         self, receiver_id: c.Hashable | ||||
|     ) -> c.Callable[[weakref.ref[c.Callable[..., t.Any]]], None]: | ||||
|         """Create a callback function to disconnect a weakly referenced | ||||
|         receiver when it is garbage collected. | ||||
|         """ | ||||
| 
 | ||||
|         def cleanup(ref: weakref.ref[c.Callable[..., t.Any]]) -> None: | ||||
|             # If the interpreter is shutting down, disconnecting can result in a | ||||
|             # weird ignored exception. Don't call it in that case. | ||||
|             if not sys.is_finalizing(): | ||||
|                 self._disconnect(receiver_id, ANY_ID) | ||||
| 
 | ||||
|         return cleanup | ||||
| 
 | ||||
|     def _make_cleanup_sender( | ||||
|         self, sender_id: c.Hashable | ||||
|     ) -> c.Callable[[weakref.ref[t.Any]], None]: | ||||
|         """Create a callback function to disconnect all receivers for a weakly | ||||
|         referenced sender when it is garbage collected. | ||||
|         """ | ||||
|         assert sender_id != ANY_ID | ||||
| 
 | ||||
|         def cleanup(ref: weakref.ref[t.Any]) -> None: | ||||
|             self._weak_senders.pop(sender_id, None) | ||||
| 
 | ||||
|             for receiver_id in self._by_sender.pop(sender_id, ()): | ||||
|                 self._by_receiver[receiver_id].discard(sender_id) | ||||
| 
 | ||||
|         return cleanup | ||||
| 
 | ||||
|     def _cleanup_bookkeeping(self) -> None: | ||||
|         """Prune unused sender/receiver bookkeeping. Not threadsafe. | ||||
| 
 | ||||
|         Connecting & disconnecting leaves behind a small amount of bookkeeping | ||||
|         data. Typical workloads using Blinker, for example in most web apps, | ||||
|         Flask, CLI scripts, etc., are not adversely affected by this | ||||
|         bookkeeping. | ||||
| 
 | ||||
|         With a long-running process performing dynamic signal routing with high | ||||
|         volume, e.g. connecting to function closures, senders are all unique | ||||
|         object instances. Doing all of this over and over may cause memory usage | ||||
|         to grow due to extraneous bookkeeping. (An empty ``set`` for each stale | ||||
|         sender/receiver pair.) | ||||
| 
 | ||||
|         This method will prune that bookkeeping away, with the caveat that such | ||||
|         pruning is not threadsafe. The risk is that cleanup of a fully | ||||
|         disconnected receiver/sender pair occurs while another thread is | ||||
|         connecting that same pair. If you are in the highly dynamic, unique | ||||
|         receiver/sender situation that has lead you to this method, that failure | ||||
|         mode is perhaps not a big deal for you. | ||||
|         """ | ||||
|         for mapping in (self._by_sender, self._by_receiver): | ||||
|             for ident, bucket in list(mapping.items()): | ||||
|                 if not bucket: | ||||
|                     mapping.pop(ident, None) | ||||
| 
 | ||||
|     def _clear_state(self) -> None: | ||||
|         """Disconnect all receivers and senders. Useful for tests.""" | ||||
|         self._weak_senders.clear() | ||||
|         self.receivers.clear() | ||||
|         self._by_sender.clear() | ||||
|         self._by_receiver.clear() | ||||
| 
 | ||||
| 
 | ||||
| class NamedSignal(Signal): | ||||
|     """A named generic notification emitter. The name is not used by the signal | ||||
|     itself, but matches the key in the :class:`Namespace` that it belongs to. | ||||
| 
 | ||||
|     :param name: The name of the signal within the namespace. | ||||
|     :param doc: The docstring for the signal. | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, name: str, doc: str | None = None) -> None: | ||||
|         super().__init__(doc) | ||||
| 
 | ||||
|         #: The name of this signal. | ||||
|         self.name: str = name | ||||
| 
 | ||||
|     def __repr__(self) -> str: | ||||
|         base = super().__repr__() | ||||
|         return f"{base[:-1]}; {self.name!r}>"  # noqa: E702 | ||||
| 
 | ||||
| 
 | ||||
| class Namespace(dict[str, NamedSignal]): | ||||
|     """A dict mapping names to signals.""" | ||||
| 
 | ||||
|     def signal(self, name: str, doc: str | None = None) -> NamedSignal: | ||||
|         """Return the :class:`NamedSignal` for the given ``name``, creating it | ||||
|         if required. Repeated calls with the same name return the same signal. | ||||
| 
 | ||||
|         :param name: The name of the signal. | ||||
|         :param doc: The docstring of the signal. | ||||
|         """ | ||||
|         if name not in self: | ||||
|             self[name] = NamedSignal(name, doc) | ||||
| 
 | ||||
|         return self[name] | ||||
| 
 | ||||
| 
 | ||||
| class _PNamespaceSignal(t.Protocol): | ||||
|     def __call__(self, name: str, doc: str | None = None) -> NamedSignal: ... | ||||
| 
 | ||||
| 
 | ||||
| default_namespace: Namespace = Namespace() | ||||
| """A default :class:`Namespace` for creating named signals. :func:`signal` | ||||
| creates a :class:`NamedSignal` in this namespace. | ||||
| """ | ||||
| 
 | ||||
| signal: _PNamespaceSignal = default_namespace.signal | ||||
| """Return a :class:`NamedSignal` in :data:`default_namespace` with the given | ||||
| ``name``, creating it if required. Repeated calls with the same name return the | ||||
| same signal. | ||||
| """ | ||||
							
								
								
									
										0
									
								
								venv/lib/python3.11/site-packages/blinker/py.typed
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								venv/lib/python3.11/site-packages/blinker/py.typed
									
										
									
									
									
										Normal file
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Tykayn
						Tykayn