Skip to content

Commit

Permalink
🔖 1.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
H2Sxxa committed Aug 30, 2024
1 parent d167db8 commit 77942fc
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 11 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "saleyo"
version = "1.1.2"
version = "1.2.0"
description = "Saleyo is a lightwight scalable Python AOP framework, easy to use and integrate."
authors = [{ name = "H2Sxxa", email = "[email protected]" }]
dependencies = []
Expand Down
41 changes: 32 additions & 9 deletions src/saleyo/base/import_broadcast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,44 @@

_initialize_flag = False

_listener: OrderedDict[Union[str, int], Callable[[str, ModuleType], Any]] = (
_listeners: OrderedDict[Union[str, int], Callable[[str, ModuleType], Any]] = (
OrderedDict()
)

_disposable_listeners: OrderedDict[
Union[str, int], Callable[[str, ModuleType], Any]
] = OrderedDict()


def add_listen_import(
listener: Callable[[str, ModuleType], Any], key: Optional[str] = None
listener: Callable[[str, ModuleType], Any],
key: Optional[str] = None,
disposable: bool = False,
):
listeners = _disposable_listeners if disposable else _listeners

hashkey = key if key else hash(listener)
if hashkey in _listener:
if hashkey in listeners:
raise Exception(f"{hashkey} Duplicate!")
_listener[hashkey] = listener
listeners[hashkey] = listener


def remove_listen_import(
key: Union[str, Callable[[str, ModuleType], Any]],
disposable: bool = False,
):
listeners = _disposable_listeners if disposable else _listeners

del listeners[key if isinstance(key, str) else hash(key)]

def remove_listen_import(key: Union[str, Callable[[str, ModuleType], Any]]):
del _listener[key if isinstance(key, str) else hash(key)]

def remove_listen_import_hash(
hash: int,
disposable: bool = False,
):
listeners = _disposable_listeners if disposable else _listeners

def remove_listen_import_hash(hash: int):
del _listener[hash]
del listeners[hash]


def initialize_import_broadcast():
Expand All @@ -37,8 +55,13 @@ def initialize_import_broadcast():
class ImportBroadCastDict(type(sys.modules)):
def __setitem__(self, key: str, value: ModuleType) -> None:
# BroadCast
for listener in _listener.values():
for listener in _listeners.values():
listener(key, value)
# disposable
for hashkey, listener in _disposable_listeners.items():
listener(key, value)
del _disposable_listeners[hashkey]

return super().__setitem__(key, value)

sys.modules = ImportBroadCastDict(sys.modules)
Expand Down
1 change: 1 addition & 0 deletions src/saleyo/decorator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

from .ancestor import Ancestor as Ancestor
from .mixin import Mixin as Mixin
from . import lazy as lazy
46 changes: 45 additions & 1 deletion src/saleyo/decorator/mixin.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Generic, Iterable, List, Union
from types import ModuleType
from typing import Callable, Generic, Iterable, List, Optional, Union

from ..base.template import MixinOperation
from ..base.toolchain import DefaultToolChain, ToolChain
Expand All @@ -11,6 +12,8 @@ class Mixin(Generic[M]):
If the target is a special class, you should custom the toolchain yourself.
When the target if a `Iterable` object, Please use [`target`]
It is recommend to use `assert isinstance(self, <target>)` at the head of
operation functions, although there may be some performance cost,
but it is worth it in most conditions.
Expand Down Expand Up @@ -106,6 +109,47 @@ def from_regex(
reverse_level=reverse_level,
)

@staticmethod
def lazy(
mixin: object,
factory: Callable[[str, ModuleType], Optional[IterableOrSingle[M]]],
toolchain: ToolChain = DefaultToolChain,
reverse_level: bool = False,
key: Optional[str] = None,
initialize: bool = True,
disposable: bool = True,
) -> Union[int, str]:
"""
Please call lazy before import a module.
when the `factory` return a non-None value, the Mixin Class will apply to target.
You can add the listener yourself to controller more details, please see `saleyo.base.import_broadcast`
initialize: initialize the import-broadcast
key: specific the key of listener, you can remove it yourself
disposable: remove listener after first Mixin
"""
from saleyo.base.import_broadcast import (
initialize_import_broadcast,
add_listen_import,
)

if initialize:
initialize_import_broadcast()

def listener(k, v):
target = factory(k, v)
if target:
Mixin(
target=target, toolchain=toolchain, reverse_level=reverse_level
).apply_from_class(mixin)

add_listen_import(listener, key, disposable=disposable)
return key if key else hash(listener)

def apply_from_class(self, mixin: T) -> T:
"""
Recommand to use it from `@Mixin`
Expand Down

0 comments on commit 77942fc

Please sign in to comment.