Source code for ReFreSH.MobileSuit.Core.SuitBuildUtils

import inspect
from inspect import Parameter, signature, getmembers
from typing import Optional, Callable, Any, get_args, get_origin, List

from ...CSharp import null_collapse, linq_first_or_default, INT_MAX
from .Services.ParsingService import IParsingService
from .SuitContext import SuitContext
from .SuitMethodParameterInfo import SuitMethodParameterInfo, TailParameterType
from ..Decorators.DecoratorUtils import get_parser, get_injected
from ..Decorators.SuitArgParser import SuitArgParserInfo
from ...DependencyInjection import ServiceProvider, ServiceDescriptor, ServiceType

SuitCommandTarget = "suit-cmd-target"
SuitCommandTargetApp = "app"
SuitCommandTargetHost = "suit"
SuitCommandTargetAppTask = "app-task"

InstanceFactory = Callable[[SuitContext], Any]


[docs] def CreateConverterFactory(T, parserInfo: SuitArgParserInfo or None) -> Callable[ [SuitContext], Callable[[str], Optional[object]]]: def converter(context: SuitContext): myT = T myParserInfo = SuitArgParserInfo('', None) if parserInfo is None else parserInfo if hasattr(myParserInfo, "Converter") and myParserInfo.Converter is not None: return myParserInfo if isinstance(get_origin(myT), type) and issubclass(get_origin(myT), List): myT = get_args(myT)[0] if isinstance(myT, type) and issubclass(myT, str): return lambda s: s return context.GetRequiredService(IParsingService).Get(myT, null_collapse(myParserInfo.Name, '')) return converter
[docs] def GetArg(parameter: Parameter, function: Callable, arg: Optional[str], context: SuitContext) -> tuple[object, int]: if arg is None: step = 0 if parameter.annotation == Parameter.empty and parameter.default == Parameter.empty: raise ValueError if issubclass(parameter.annotation, SuitContext): return context, step service = context.GetService(parameter.annotation) return parameter.default if service is None else service step = 1 return CreateConverterFactory(parameter.annotation, get_parser(function, parameter.name))(context)(arg), step
[docs] def GetArrayArg(parameter: Parameter, function: Callable, argArray: list[str], context: SuitContext) -> object: otype = get_args(parameter.annotation)[0] array = list[otype]() convert = CreateConverterFactory( otype, get_parser(function, parameter.name))(context) for arg in argArray: array.append(convert(arg)) return array, len(argArray)
def __GetParametersFromFunc(func: Callable) -> List[Parameter]: sig = signature(func) parameters = [param for (_, param) in filter(lambda x: x[0] != 'self', sig.parameters.items())] return parameters
[docs] def GetMethodParameterInfo(func: Callable) -> SuitMethodParameterInfo: parameters = __GetParametersFromFunc(func) suitMethodParameterInfo = SuitMethodParameterInfo() originCount = len(parameters) parameters = [p for p in parameters if not get_injected(func, p.name)] if originCount == 0: suitMethodParameterInfo.TailParameterType = TailParameterType.NoParameter else: if len(parameters) == 0: suitMethodParameterInfo.TailParameterType = TailParameterType.Normal tailParamAnnotation = get_origin(parameters[-1].annotation) if inspect.isclass(tailParamAnnotation) and issubclass(tailParamAnnotation, List): suitMethodParameterInfo.TailParameterType = TailParameterType.Array # TODO: DynamicParameter support # elif parameters[-1].ParameterType.GetInterface("IDynamicParameter") is not None: # suitMethodParameterInfo.TailParameterType = TailParameterType.DynamicParameter else: suitMethodParameterInfo.TailParameterType = TailParameterType.Normal suitMethodParameterInfo.MaxParameterCount = len( parameters) if suitMethodParameterInfo.TailParameterType == TailParameterType.Normal else INT_MAX suitMethodParameterInfo.NonArrayParameterCount = len( parameters) if suitMethodParameterInfo.TailParameterType == TailParameterType.Normal else len( parameters) - 1 i = suitMethodParameterInfo.NonArrayParameterCount - 1 while i >= 0 and parameters[i].default != Parameter.empty: i -= 1 suitMethodParameterInfo.MinParameterCount = i + 1 suitMethodParameterInfo.NonArrayParameterCount = originCount if suitMethodParameterInfo.TailParameterType == TailParameterType.Normal else originCount - 1 return suitMethodParameterInfo
[docs] def CreateInstance(otype, s: SuitContext) -> Optional[Any]: service = s.GetService(otype) if service is not None: return service constructor = linq_first_or_default(getmembers(otype), lambda x: x[0] == '__init__')[1] args = GetArgs(constructor, [], s) return otype(*args)
[docs] def CreateInstanceWithProvider(otype, s: ServiceProvider) -> Optional[Any]: service = s.GetService(otype) if service is not None: return service return ServiceDescriptor(otype, ServiceType.Singleton, None, None, otype).CreateInstance(s)
[docs] def GetArgsInternal(func: Callable, parameterInfo: SuitMethodParameterInfo, args: List[str], context: SuitContext) -> Optional[List[Optional[Any]]]: parameters = __GetParametersFromFunc(func) pass_: List[Any] = [None] * len(parameters) if parameterInfo.TailParameterType == TailParameterType.NoParameter: return pass_ i = 0 j = 0 try: for i in range(parameterInfo.NonArrayParameterCount): if j < len(args): pass_[i], step = GetArg(parameters[i], func, args[j], context) j += step else: pass_[i], _ = GetArg(parameters[i], func, None, context) if parameterInfo.TailParameterType == TailParameterType.Normal: return pass_ # TODO: DynamicParameter support # if parameterInfo.TailParameterType == TailParameterType.DynamicParameter: # dynamicParameter = parameters[-1].ParameterType.Assembly.CreateInstance( # parameters[-1].ParameterType.FullName or parameters[-1].ParameterType.Name) # if not dynamicParameter.Parse(args[i:] if i < len(args) else [], context): # return None # pass_[i] = dynamicParameter # return pass_ if i < len(args): pass_[i], step = GetArrayArg(parameters[-1], func, args[i:], context) i += step else: pass_[i] = [] return pass_ except ValueError: return None
[docs] def GetArgs(func: Callable, args: List[str], context: SuitContext) -> Optional[List[Optional[Any]]]: return GetArgsInternal(func, GetMethodParameterInfo(func), args, context)