diff --git a/excore/config/__init__.py b/excore/config/__init__.py index 7b0fb2c..0030292 100644 --- a/excore/config/__init__.py +++ b/excore/config/__init__.py @@ -7,6 +7,7 @@ ModuleNode, ReusedNode, VariableReference, + register_special_flag, silent, ) from .parse import ConfigDict, set_primary_fields @@ -24,5 +25,6 @@ "InterNode", "ModuleNode", "ReusedNode", + "register_special_flag", "VariableReference", ] diff --git a/excore/config/models.py b/excore/config/models.py index b45abff..341d87b 100644 --- a/excore/config/models.py +++ b/excore/config/models.py @@ -25,7 +25,7 @@ NoCallSkipFlag = Self ConfigHookSkipFlag = Type[None] - SpecialFlag = Literal["@", "!", "$", "&", "*", ""] + SpecialFlag = Literal["@", "!", "$", "&", ""] __all__ = ["silent"] @@ -34,11 +34,12 @@ INTER_FLAG: Literal["!"] = "!" CLASS_FLAG: Literal["$"] = "$" REFER_FLAG: Literal["&"] = "&" -DETAI_FLAG: Literal["*"] = "*" OTHER_FLAG: Literal[""] = "" +FLAG_PATTERN = re.compile(r"^([@!$&])(.*)$") LOG_BUILD_MESSAGE = True DO_NOT_CALL_KEY = "__no_call__" +SPECIAL_FLAGS = [OTHER_FLAG, INTER_FLAG, REUSE_FLAG, CLASS_FLAG, REFER_FLAG] def silent() -> None: @@ -60,8 +61,7 @@ def _is_special(k: str) -> tuple[str, SpecialFlag]: Returns: Tuple[str, str]: A tuple containing the modified string and the special character. """ - pattern = re.compile(r"^([@!$&*])(.*)$") - match = pattern.match(k) + match = FLAG_PATTERN.match(k) if match: return match.group(2), match.group(1) # type: ignore return k, "" @@ -140,6 +140,10 @@ def __rshift__(self, __other: ModuleNode) -> Self: __other.update(self) return self + @classmethod + def __excore_check_target_type__(cls, target_type) -> bool: + return False + @classmethod def from_str(cls, str_target: str, params: NodeParams | None = None) -> ModuleNode: node = cls(_str_to_target(str_target)) @@ -171,6 +175,10 @@ def from_node(cls, _other: ModuleNode) -> ModuleNode: class InterNode(ModuleNode): priority = 2 + @classmethod + def __excore_check__(cls, target_type) -> bool: + return cls.priority + target_type.priority == 5 + class ConfigHookNode(ModuleNode): def __call__(self, **params: NodeParams) -> NodeInstance | ConfigHookSkipFlag | Hook: @@ -194,6 +202,10 @@ class ClassNode(InterNode): def __call__(self) -> NodeClassType | FunctionType: # type: ignore return self.cls + @classmethod + def __excore_check__(cls, target_type) -> bool: + return cls.priority + target_type.priority == 5 + class ChainedInvocationWrapper(ConfigArgumentHook): def __init__(self, node: ModuleNode, attrs: list[str]) -> None: @@ -300,3 +312,12 @@ def __repr__(self) -> str: INTER_FLAG: InterNode, CLASS_FLAG: ClassNode, } + + +def register_special_flag(flag: str, target_module: ModuleNode, force: bool = False) -> None: + if not force and flag in SPECIAL_FLAGS: + raise ValueError(f"Special flag `{flag}` already exist.") + SPECIAL_FLAGS.append(flag) + global FLAG_PATTERN + FLAG_PATTERN = re.compile(rf"^([{''.join(SPECIAL_FLAGS)}])(.*)$") + _dispatch_module_node[flag] = target_module # type: ignore diff --git a/excore/config/parse.py b/excore/config/parse.py index 5d85dc9..edd794d 100644 --- a/excore/config/parse.py +++ b/excore/config/parse.py @@ -370,7 +370,8 @@ def _parse_single_param( self.current_field = cache_field # InterNode and ReusedNode - if ori_type and ori_type.priority + target_type.priority == 5: + # if ori_type and ori_type.priority + target_type.priority == 5: + if ori_type and ori_type.__excore_check_target_type__(target_type): raise CoreConfigParseError( f"Error when parsing param `{ori_name}`, " f"target_type is `{target_type}`, but got original_type `{ori_type}`. "