Skip to content

Commit

Permalink
🎨 Code Optimize
Browse files Browse the repository at this point in the history
  • Loading branch information
H2Sxxa committed Mar 15, 2024
1 parent 9528b19 commit 13cdc5d
Show file tree
Hide file tree
Showing 18 changed files with 218 additions and 108 deletions.
14 changes: 5 additions & 9 deletions src/saleyo/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Saleyo is A module to modify external python code in runtime.
Saleyo is a module to modify external python code in runtime.
The implements are in `mixin`.
Expand All @@ -10,11 +10,7 @@
The `base` module is used to extend your own `mixin` method.
"""

from . import decorator, function, mixin, base

__all__ = [
"decorator",
"function",
"mixin",
"base",
]
from . import operation as operation
from . import base as base
from . import mixin as mixin
from .mixin import Mixin as Mixin
10 changes: 3 additions & 7 deletions src/saleyo/base/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
from . import typing, template, toolchain

__all__ = [
"typing",
"template",
"toolchain",
]
from . import typing as typing
from . import template as template
from . import toolchain as toolchain
8 changes: 6 additions & 2 deletions src/saleyo/base/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ class MixinOperation(Generic[T], ABC):
"""
The MixinOperation is the base of All Operation.
The generic `MixinOperation` is the type of argument
The generic `MixinOperation` is the type of argument.
`level` will affect to the mixin order, default to `1`.
"""

argument: T
level: int

def __init__(self, argument: T) -> None:
def __init__(self, argument: T, level=1) -> None:
self.argument = argument
self.level = level

def mixin(self, target: Type, toolchain: ToolChain = ToolChain()) -> None:
raise NotImplementedError(
Expand Down
2 changes: 1 addition & 1 deletion src/saleyo/base/toolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class InvokeEvent(Generic[T]):
argument: Dict[str, Any]

@staticmethod
def from_call(target: Callable[..., Any], *args, **kwargs) -> "InvokeEvent":
def from_call(target: Callable[..., T], *args, **kwargs) -> "InvokeEvent[T]":
argument = {}
function_parameters = signature(target).parameters
arg_names = list(function_parameters.keys())
Expand Down
Empty file removed src/saleyo/decorator.py
Empty file.
Empty file removed src/saleyo/function.py
Empty file.
29 changes: 19 additions & 10 deletions src/saleyo/mixin/mixin.py → src/saleyo/mixin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from typing import List, Type

from ..base.template import MixinOperation
from ..base.toolchain import ToolChain
from ..base.typing import T, Target
from .base.template import MixinOperation
from .base.toolchain import ToolChain
from .base.typing import T, Target


class Mixin:
Expand All @@ -12,25 +12,34 @@ class Mixin:

target_class: List[Type]
toolchain: ToolChain
reverse_level: bool

def __init__(
self,
target_class: Target,
toolchain: ToolChain = ToolChain(),
reverse_level: bool = False,
) -> None:
self.target_class = (
target_class if isinstance(target_class, list) else [target_class]
)
self.toolchain = toolchain
self.reverse_level = reverse_level

def collect(self, mixin: T) -> T:
for member in map(
lambda name: self.toolchain.tool_getattr(mixin, name),
filter(lambda name: not name.startswith("_"), dir(mixin)),
):
if not isinstance(member, MixinOperation):
continue

members: List[MixinOperation] = sorted(
filter(
lambda member: isinstance(member, MixinOperation),
map(
lambda name: self.toolchain.tool_getattr(mixin, name),
filter(lambda name: not name.startswith("_"), dir(mixin)),
),
),
key=lambda member: member.level,
reverse=self.reverse_level,
)

for member in members:
for target in self.target_class:
member.mixin(target=target, toolchain=self.toolchain)
return mixin
Expand Down
13 changes: 0 additions & 13 deletions src/saleyo/mixin/__init__.py

This file was deleted.

13 changes: 0 additions & 13 deletions src/saleyo/mixin/inject.py

This file was deleted.

33 changes: 0 additions & 33 deletions src/saleyo/mixin/intercept.py

This file was deleted.

5 changes: 5 additions & 0 deletions src/saleyo/operation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from .accessor import Accessor as Accessor
from .overwrite import OverWrite as OverWrite
from .processor import Processor as Processor
from .intercept import Intercept as Intercept, InvokeEvent as InvokeEvent
from .hook import Pre as Pre, Post as Post
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ class Accessor(Generic[T], MixinOperation[str]):

_inner: Optional[T]

@staticmethod
def configure(level: int = 1):
return lambda argument: Accessor(
argument=argument,
level=level,
)

def mixin(self, target: Type, toolchain: ToolChain = ToolChain()) -> None:
self._inner = toolchain.tool_getattr(
target,
Expand Down
79 changes: 79 additions & 0 deletions src/saleyo/operation/hook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
from typing import Callable, Optional, Type

from ..base.typing import RT, T
from ..base.toolchain import ToolChain
from ..base.template import MixinOperation


class Post(MixinOperation[Callable[[T], RT]]):
target_name: Optional[str]

def __init__(
self,
argument: Callable[[T], RT],
target_name: Optional[str] = None,
level: int = 1,
) -> None:
super().__init__(argument, level)
self.target_name = target_name

@staticmethod
def configure(
level: int = 1,
target_name: Optional[str] = None,
):
return lambda argument: Post(
argument=argument,
target_name=target_name,
level=level,
)

def mixin(self, target: Type, toolchain: ToolChain = ToolChain()) -> None:
target_name = (
self.target_name if self.target_name is not None else self.argument.__name__
)
native_function = toolchain.tool_getattr(target, target_name)

def post(*args, **kwargs):
result = native_function(*args, **kwargs)
self.argument(result)
return result

return toolchain.tool_setattr(target, target_name, post)


class Pre(MixinOperation[Callable[..., RT]]):
target_name: Optional[str]

def __init__(
self,
argument: Callable[[T], RT],
target_name: Optional[str] = None,
level: int = 1,
) -> None:
super().__init__(argument, level)
self.target_name = target_name

@staticmethod
def configure(
level: int = 1,
target_name: Optional[str] = None,
):
return lambda argument: Post(
argument=argument,
target_name=target_name,
level=level,
)

def mixin(self, target: Type, toolchain: ToolChain = ToolChain()) -> None:
target_name = (
self.target_name if self.target_name is not None else self.argument.__name__
)
native_function = toolchain.tool_getattr(target, target_name)

def pre(*args, **kwargs):
self.argument(*args, **kwargs)
result = native_function(*args, **kwargs)
return result

return toolchain.tool_setattr(target, target_name, pre)
61 changes: 61 additions & 0 deletions src/saleyo/operation/intercept.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from typing import Any, Callable, Generic, Optional, Type

from ..base.typing import RT, T
from ..base.toolchain import InvokeEvent, ToolChain
from ..base.template import MixinOperation


class Intercept(
Generic[T, RT], MixinOperation[Callable[[InvokeEvent[T]], InvokeEvent[RT]]]
):
"""
The `Intercept` allow you to intercept the arguments before invoking target method.
Then, you can handle these arguments in your own functions.
"""

target_name: Optional[str]

def __init__(
self,
argument: Callable[[InvokeEvent[T]], InvokeEvent[RT]],
level: int = 1,
target_name: Optional[str] = None,
) -> None:
super().__init__(argument, level)
self.target_name = target_name

@staticmethod
def configure(
level: int = 1,
target_name: Optional[str] = None,
) -> Callable[[Callable[[InvokeEvent[T]], InvokeEvent[RT]]], "Intercept[T, RT]"]:
return lambda argument: Intercept(
argument=argument,
level=level,
target_name=target_name,
)

def mixin(
self,
target: Type,
toolchain: ToolChain = ToolChain(),
) -> None:
target_name = (
self.target_name if self.target_name is not None else self.argument.__name__
)
native_function = toolchain.tool_getattr(
target,
target_name,
)

def invoke(*args, **kwargs) -> Any:
return self.argument(
InvokeEvent.from_call(native_function, *args, **kwargs)
).invoke()

return toolchain.tool_setattr(
target,
target_name,
invoke,
)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from types import MethodType
from typing import Callable, Optional, Type

from ..base.toolchain import ToolChain
from ..base.template import MixinOperation

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,29 @@ class Processor(MixinOperation[Callable[[str], str]]):
def __init__(
self,
argument: Callable[[str], str],
level: int = 1,
target_name: Optional[str] = None,
prefix_indent: Optional[int] = None,
module: Optional[ModuleType] = None,
extra_namespace: Optional[NameSpace] = None,
) -> None:
super().__init__(argument)
super().__init__(argument, level)
self.target_name = target_name
self.prefix_indent = prefix_indent
self.module = module
self.extra_namespace = extra_namespace

@staticmethod
def configure(
level: int = 1,
target_name: Optional[str] = None,
prefix_indent: Optional[int] = None,
module: Optional[ModuleType] = None,
extra_namespace: Optional[NameSpace] = None,
) -> Callable[[Callable[[str], str]], "Processor"]:
return lambda argument: Processor(
argument=argument,
level=level,
prefix_indent=prefix_indent,
target_name=target_name,
module=module,
Expand Down
20 changes: 1 addition & 19 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1 @@
from saleyo.base.toolchain import InvokeEvent
from saleyo.mixin import Mixin
from saleyo.mixin.intercept import Intercept


class Foo:
def demo(self, hello, bad=0):
print("goodbye~")


@Mixin(target_class=Foo)
class A:
@Intercept
@staticmethod
def demo(_: InvokeEvent[None]):
return InvokeEvent.from_call(lambda: print("hello world"))


Foo().demo(1)
from . import intercept as intercept
Loading

0 comments on commit 13cdc5d

Please sign in to comment.