Skip to content

Commit

Permalink
🎨 Optimize the typing; add from_name and from_regex to Mixin
Browse files Browse the repository at this point in the history
  • Loading branch information
H2Sxxa committed Mar 18, 2024
1 parent df637cb commit a751c02
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/saleyo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
https://pypi.org/project/saleyo/
"""

from . import operation as operation
from . import base as base
from . import mixin as mixin
from . import operation as operation
from .mixin import Mixin as Mixin
from .operation import Accessor as Accessor
from .operation import Processor as Processor
Expand Down
25 changes: 16 additions & 9 deletions src/saleyo/base/typing.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
from typing import Any, Dict, List, ParamSpec, Type, TypeVar, Union
from typing import Any, Dict, Iterable, ParamSpec, TypeVar, Union


# Generic

Target = Union[Type[Any], List[Type[Any]]]
"""
`Target` is the target of `@Mixin`, it's the alias of `Union[Type[Any], List[Type[Any]]]`
"""
NameSpace = Dict[str, Any]
"""
`NameSpace` is the alias of `Dict[str, Any]`
"""
RT = TypeVar("RT")
"""
`RT` means `Return Type`
Expand All @@ -20,3 +15,15 @@
"""
`P` means `Params`
"""

# Alias

NameSpace = Dict[str, Any]
"""
`NameSpace` is the alias of `Dict[str, Any]`
"""

IterableOrSingle = Union[T, Iterable[T]]
"""
`IterableOrSingle[T]` is the alias of `Union[T, List[T]]`
"""
81 changes: 76 additions & 5 deletions src/saleyo/mixin.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from typing import List
from typing import Any, Iterable, List, Type

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


class Mixin:
Expand All @@ -14,20 +14,91 @@ class Mixin:
Allow to have more than one target, but that's not recommended.
"""

target: Target
target: IterableOrSingle[Type[Any]]
toolchain: ToolChain
reverse_level: bool

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

@staticmethod
def from_name(
target: IterableOrSingle[str],
toolchain: ToolChain = ToolChain(),
reverse_level: bool = False,
qualname: bool = False,
) -> "Mixin":
"""
Will find target classes from `object.__subclasses__()` from class name or qualname.
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.
"""

target = target if isinstance(target, Iterable) else [target]

return Mixin(
list(
filter(
lambda clazz: clazz.__name__ in target
if qualname
else clazz.__qualname__ in target,
object.__subclasses__(),
)
),
toolchain=toolchain,
reverse_level=reverse_level,
)

@staticmethod
def from_regex(
pattern: str,
pattern_flags: int = 0,
toolchain: ToolChain = ToolChain(),
reverse_level: bool = False,
qualname: bool = False,
full_match: bool = False,
) -> "Mixin":
"""
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`.
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.
"""
import re

regex_pattern = re.compile(pattern=pattern, flags=pattern_flags)
matcher = regex_pattern.fullmatch if full_match else regex_pattern.match

return Mixin(
list(
filter(
lambda clazz: matcher(
clazz.__name__ if qualname else clazz.__qualname__
)
is not None,
object.__subclasses__(),
)
),
toolchain=toolchain,
reverse_level=reverse_level,
)

def collect(self, mixin: T) -> T:
members: List[MixinOperation] = sorted(
filter(
Expand Down

0 comments on commit a751c02

Please sign in to comment.