Skip to content

Commit

Permalink
🎨 Ruff Lint
Browse files Browse the repository at this point in the history
  • Loading branch information
H2Sxxa committed May 24, 2024
1 parent f467320 commit 6b42cee
Show file tree
Hide file tree
Showing 26 changed files with 231 additions and 145 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.1"
version = "1.1.2"
description = "Saleyo is a lightwight scalable Python AOP framework, easy to use and integrate."
authors = [{ name = "H2Sxxa", email = "[email protected]" }]
dependencies = []
Expand Down
15 changes: 15 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[lint]
select = [
# pycodestyle
"E",
# Pyflakes
"F",
# pyupgrade
"UP",
# flake8-bugbear
"B",
# flake8-simplify
"SIM",
# isort
"I",
]
27 changes: 13 additions & 14 deletions src/saleyo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,23 @@
"""

from . import base as base
from . import mixin as mixin
from . import operation as operation
from .mixin import Mixin as Mixin
from .base.template import MixinOperation as MixinOperation
from .base.toolchain import Arguments as Arguments
from .base.toolchain import CPyToolChain as CPyToolChain
from .base.toolchain import GCToolChain as GCToolChain
from .base.toolchain import InvokeEvent as InvokeEvent
from .base.toolchain import ToolChain as ToolChain
from .decorator import Ancestor as Ancestor
from .decorator import Mixin as Mixin
from .operation import Accessor as Accessor
from .operation import Alias as Alias
from .operation import Del as Del
from .operation import FunctionAccessor as FunctionAccessor
from .operation import Processor as Processor
from .operation import Insert as Insert
from .operation import Intercept as Intercept
from .operation import OverWrite as OverWrite
from .operation import Pre as Pre
from .operation import Post as Post
from .operation import Del as Del
from .operation import Pre as Pre
from .operation import Processor as Processor
from .operation import ReName as ReName
from .operation import Alias as Alias
from .operation import Ancestor as Ancestor
from .operation import Insert as Insert
from .base.toolchain import ToolChain as ToolChain
from .base.toolchain import Arguments as Arguments
from .base.toolchain import InvokeEvent as InvokeEvent
from .base.toolchain import CPyToolChain as CPyToolChain
from .base.toolchain import GCToolChain as GCToolChain
from .base.template import MixinOperation as MixinOperation
2 changes: 1 addition & 1 deletion src/saleyo/base/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from . import typing as typing
from . import template as template
from . import toolchain as toolchain
from . import typing as typing
11 changes: 6 additions & 5 deletions src/saleyo/base/template.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from abc import ABC
from typing import Any, Generic

from .toolchain import ToolChain
from .typing import T, M
from .toolchain import DefaultToolChain, ToolChain
from .typing import M, T


class MixinOperation(Generic[T], ABC):
Expand All @@ -12,8 +12,9 @@ class MixinOperation(Generic[T], ABC):
The generic `MixinOperation` is the type of argument.
`level` will affect to the mixin order, default `1`.
If you call the `MixinOperation` or call the subclass of this, it will call the `MixinOperation.argument`
If you call the `MixinOperation` or call the subclass of this,
it will call the `MixinOperation.argument`
"""

argument: T
Expand All @@ -23,7 +24,7 @@ def __init__(self, argument: T, level=1) -> None:
self.argument = argument
self.level = level

def mixin(self, target: M, toolchain: ToolChain = ToolChain()) -> None:
def mixin(self, target: M, toolchain: ToolChain = DefaultToolChain) -> None:
raise NotImplementedError(
f"Not Ready to use this Operation to modify '{target}' via '{toolchain}'"
)
Expand Down
31 changes: 21 additions & 10 deletions src/saleyo/base/toolchain.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from ctypes import py_object as _py_object, POINTER as _POINTER, cast as _cast
from types import FunctionType
from ctypes import POINTER as _POINTER
from ctypes import cast as _cast
from ctypes import py_object as _py_object
from dataclasses import dataclass
from gc import get_referents as _get_referents
from types import FunctionType
from typing import Any, Callable, Dict, Generic, Optional

from ..base.typing import P, T, NameSpace
from ..base.typing import NameSpace, P, T


@dataclass
Expand All @@ -21,6 +23,8 @@ class ToolChain:
tool_delattr: Callable[[Any, str], None] = delattr


DefaultToolChain = ToolChain()

GCToolChain = ToolChain(
tool_getattr=lambda _object, _name: _get_referents(_object.__dict__)[0][_name],
tool_hasattr=lambda _object, _name: _name in _get_referents(_object.__dict__)[0],
Expand All @@ -32,9 +36,11 @@ class ToolChain:
),
)
"""
GC ToolChain use the `get_referents` functions in `gc` and it can modify some special class.
GC ToolChain use the `get_referents` functions in `gc` and
it can modify some special class.
Notice: There is no guarantee that it can modify any class, and this method is rude and dangerous, avoid using it in produce environment.
Notice: There is no guarantee that it can modify any class,
and this method is rude and dangerous, avoid using it in produce environment.
"""


Expand All @@ -53,15 +59,18 @@ def _cpy_get_dict(_object: Any) -> Dict[str, Any]:
tool_delattr=lambda _object, _name: _cpy_get_dict(_object).__delitem__(_name),
)
"""
`CPyToolChain` use the `ctypes` to modify class, it's dangerous than other default toolchains.
`CPyToolChain` use the `ctypes` to modify class,
it's dangerous than other default toolchains.
Notice: There is no guarantee that it can modify any class, and this method is rude and dangerous, avoid using it in produce environment.
Notice: There is no guarantee that it can modify any class,
and this method is rude and dangerous, avoid using it in produce environment.
"""


class Container:
"""
Container is A Class to keep a namespace and use this namespace to define function / variable / ...
Container is A Class to keep a namespace and
use this namespace to define function / variable / ...
"""

environment: NameSpace
Expand Down Expand Up @@ -90,7 +99,8 @@ def define_function(

class Arguments(Generic[P]):
"""
`Argument` is used to call function, the Generic `P` is the params of target function.
`Argument` is used to call function,
the Generic `P` is the params of target function.
"""

def __init__(self, *args: P.args, **kwargs: P.kwargs) -> None:
Expand All @@ -103,7 +113,8 @@ def __str__(self) -> str:

class InvokeEvent(Generic[P, T]):
"""
A `InvokeEvent` includes the target function and the arguments to call this functions.
A `InvokeEvent` includes the target function and the arguments to
call this functions.
"""

target: Callable[P, T]
Expand Down
1 change: 0 additions & 1 deletion src/saleyo/base/typing.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from types import ModuleType
from typing import Any, Dict, Iterable, ParamSpec, Type, TypeVar, Union


# Generic

RT = TypeVar("RT")
Expand Down
6 changes: 6 additions & 0 deletions src/saleyo/decorator/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
"""
The `decorator` should be used to decorate a class.
"""

from .ancestor import Ancestor as Ancestor
from .mixin import Mixin as Mixin
45 changes: 45 additions & 0 deletions src/saleyo/decorator/ancestor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from typing import Any, Generic, Type

from ..base.toolchain import DefaultToolChain, ToolChain
from ..base.typing import T


class Ancestor(Generic[T]):
"""
Ancestor will add the `ancestor_class` to `target.__bases__`.
(Please see `__call__` method)
Please ensure the `target.__bases__` is not `(object,)`, this decorator requires
the target has at least one super class.
If `reverse`, the `argument` will add to the head of `target.__bases__`.
Don't try to use it with external code and `module`, it will crash.
"""

reverse: bool
target: Type[Any]
toolchain: ToolChain

def __init__(
self, target: Type[Any], toolchain: ToolChain = DefaultToolChain, reverse=False
) -> None:
self.reverse = reverse
self.target = target
self.toolchain = toolchain

def __call__(self, ancestor_class: Type[T]) -> Type[T]:
assert self.target.__bases__ != (object,)

self.toolchain.tool_setattr(
self.target,
"__bases__",
(ancestor_class, *self.toolchain.tool_getattr(self.target, "__bases__"))
if self.reverse
else (
*self.toolchain.tool_getattr(self.target, "__bases__"),
ancestor_class,
),
)

return ancestor_class
35 changes: 21 additions & 14 deletions src/saleyo/mixin.py → src/saleyo/decorator/mixin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from typing import Generic, Iterable, List, Union

from .base.template import MixinOperation
from .base.toolchain import ToolChain
from .base.typing import M, T, IterableOrSingle
from ..base.template import MixinOperation
from ..base.toolchain import DefaultToolChain, ToolChain
from ..base.typing import IterableOrSingle, M, T


class Mixin(Generic[M]):
Expand All @@ -11,7 +11,9 @@ class Mixin(Generic[M]):
If the target is a special class, you should custom the toolchain yourself.
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.
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.
Allow to have more than one target, but that's not recommended.
"""
Expand All @@ -23,7 +25,7 @@ class Mixin(Generic[M]):
def __init__(
self,
target: IterableOrSingle[M],
toolchain: ToolChain = ToolChain(),
toolchain: ToolChain = DefaultToolChain,
reverse_level: bool = False,
) -> None:
self.target = target if isinstance(target, Iterable) else [target]
Expand All @@ -33,18 +35,20 @@ def __init__(
@staticmethod
def from_name(
target: IterableOrSingle[str],
toolchain: ToolChain = ToolChain(),
toolchain: ToolChain = DefaultToolChain,
reverse_level: bool = False,
qualname: bool = False,
) -> "Mixin":
"""
Will find target classes from `object.__subclasses__()` from class name or qualname.
Will find target classes via `object.__subclasses__()`.
If want to find a class named `Foo`, default use the `Foo` to match, it will use `module.to.Foo` to match when `qualname` enabled.
If want to find a class named `Foo`, default use the `Foo` to match,
it will use `module.to.Foo` to match when `qualname` enabled.
Please use this after the definition of target class.
The method may takes lots of time when there are a whole lot classes, recommand to use `@Mixin()` directly if you can.
The method may takes lots of time when there are a whole lot classes,
recommand to use `@Mixin()` directly if you can.
"""

target = target if isinstance(target, Iterable) else [target]
Expand All @@ -64,21 +68,24 @@ def from_name(
def from_regex(
pattern: str,
pattern_flags: int = 0,
toolchain: ToolChain = ToolChain(),
toolchain: ToolChain = DefaultToolChain,
reverse_level: bool = False,
qualname: bool = False,
full_match: bool = False,
) -> "Mixin":
"""
Will use regex pattern to find target classes from the `object.__subclasses__()`.
Will use regex pattern to find target classes from the `object.__subclasses__()`
The `pattern` will convert to a `Pattern[str]` via `re.complie` and you can provide flags in `pattern_flags`.
The `pattern` will convert to a `Pattern[str]` via `re.complie` and
you can provide flags in `pattern_flags`.
If want to find a class named `Foo`, default use the `Foo` to match, it will use `module.to.Foo` to match when `qualname` enabled.
If want to find a class named `Foo`, default use the `Foo` to match,
it will use `module.to.Foo` to match when `qualname` enabled.
Please use this after the definition of target class.
The method may takes lots of time when there are a whole lot classes, recommand to use `@Mixin()` directly if you can.
The method may takes lots of time when there are a whole lot classes,
recommand to use `@Mixin()` directly if you can.
"""
import re

Expand Down
19 changes: 11 additions & 8 deletions src/saleyo/operation/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
"""
The `operations` always inner a class and call by `@Mixin` decorator.
"""

from .accessor import Accessor as Accessor
from .accessor import FunctionAccessor as FunctionAccessor
from .overwrite import OverWrite as OverWrite
from .processor import Processor as Processor
from .accessor import FunctionAccessor as FunctionAccessor
from .hook import Post as Post
from .hook import Pre as Pre
from .intercept import Intercept as Intercept
from .ancestor import Ancestor as Ancestor
from .modify import ReName as ReName
from .modify import Del as Del
from .modify import Alias as Alias
from .modify import Del as Del
from .modify import Insert as Insert
from .hook import Pre as Pre
from .hook import Post as Post
from .modify import ReName as ReName
from .overwrite import OverWrite as OverWrite
from .processor import Processor as Processor
Loading

0 comments on commit 6b42cee

Please sign in to comment.