import inspect
from abc import ABC, abstractmethod
from typing import Iterable, Callable, Optional, Any, List
from . import SuitBuildUtils
from ..Decorators import DecoratorUtils
from ...CSharp import nameof
from .SuitContext import SuitContext
from .SuitMethodShell import SuitMethodShell
from .SuitShell import SuitShell, MemberType
from ..RequestStatus import RequestStatus
[docs]
class ISuitShellCollection(ABC):
"""A collection contains ordered suit shell members."""
[docs]
@abstractmethod
def Members(self) -> Iterable[SuitShell]:
"""Ordered members of this"""
pass
[docs]
class SuitObjectShell(SuitShell, ISuitShellCollection):
"""Represents an object in Mobile Suit."""
def __init__(self, typedef, factory: Callable[[SuitContext], Any], info, name):
super().__init__(typedef, factory, name)
self._instanceFactory = factory
self._subSystems = []
for (name, member) in inspect.getmembers(typedef):
if name.startswith("__") or DecoratorUtils.is_ignored(member):
continue
if inspect.isfunction(member):
self.AddMethod(member)
elif isinstance(member, property):
self.AddProperty(name, member)
self._subSystems.sort(key=lambda x: (
x.AbsoluteName.lower(), x.MemberCount))
self._info = info
@property
def MemberCount(self):
return len(self._subSystems)
[docs]
def Members(self):
return self._subSystems.copy()
[docs]
@classmethod
def FromInstanceProperty(cls, name, prop, instanceFactory) -> Optional:
info = DecoratorUtils.get_info(prop.fget)
sig = inspect.signature(prop.fget).return_annotation
if sig == inspect.Parameter.empty:
return None
sh = cls(sig,
lambda c: getattr(instanceFactory(c), name),
info if info is not None else name,
name)
sh.Type = MemberType.FieldWithInfo if info is not None else MemberType.FieldWithoutInfo
if info is None:
sh._info = SuitObjectShell.GetMemberInfo(sh)
return sh
[docs]
@classmethod
def FromInstance(cls, typedef, instanceFactory, name=""):
info = DecoratorUtils.get_info(typedef)
sh = cls(typedef,
instanceFactory,
info if info is not None else nameof(typedef),
name)
sh.Type = MemberType.FieldWithInfo if info is not None else MemberType.FieldWithoutInfo
if info is None:
sh._info = SuitObjectShell.GetMemberInfo(sh)
return sh
[docs]
@classmethod
def FromType(cls, typedef, name=""):
def InstanceFactory(s):
return SuitBuildUtils.CreateInstance(typedef, s.ServiceProvider) or object()
info = DecoratorUtils.get_info(typedef)
return cls(typedef, InstanceFactory, info if info is not None else nameof(typedef), name)
[docs]
def AddMethod(self, method):
self._subSystems.append(SuitMethodShell.FromInstance(
method, self._instanceFactory))
[docs]
def AddProperty(self, name: str, prop: property):
self._subSystems.append(self.FromInstanceProperty(
name, prop, self._instanceFactory))
[docs]
async def Execute(self, context: SuitContext):
origin = context.Request
if self.AbsoluteName:
context.Request = origin[1:]
for sys in filter(lambda x: x.MayExecute(context.Request), self._subSystems):
await sys.Execute(context)
if context.RequestStatus != RequestStatus.NotHandled:
return
context.Request = origin
[docs]
def MayExecute(self, request: List[str]) -> bool:
if not self.AbsoluteName:
return len(request) > 0 and any(sys.MayExecute(request) for sys in self._subSystems)
return len(request) > 1 and request[0].lower() in self.FriendlyNames and any(
sys.MayExecute(request[1:]) for sys in self._subSystems)
[docs]
@staticmethod
def GetMemberInfo(sh) -> str:
infoSb = ''
if sh.MemberCount > 0:
i = 0
for sys in sh.Members():
infoSb += sys.AbsoluteName
if isinstance(sys, SuitObjectShell):
infoSb += "()"
elif isinstance(sys, SuitMethodShell):
infoSb += "{}"
infoSb += ','
i += 1
if i <= 5:
continue
infoSb += "...,"
break
return infoSb[:-1]
return ""