ReflectionInstance
ReflectionInstance inspects an already constructed object: its current data, defining class, methods, properties and signatures. Use it for diagnostics, adapters and extensions that need to examine a service without constructing another instance. It does not execute discovered methods or resolve their dependencies.
Quick start
Section titled “Quick start”For data belonging to an imported class, construct a wrapper around the object.
from orionis.introspection import ReflectionInstancefrom orionis.support.types import StdClass
record = StdClass(status="ready")record_reflection = ReflectionInstance(record)assert record_reflection.getPublicAttributes() == {"status": "ready"}assert record_reflection.getInstance() is recordPrepare an importable object
Section titled “Prepare an importable object”Save this example class in app/services/report_service.py. Later sections reuse service and reflected. The range of members lets you verify every filter; an application only needs the members it actually uses.
class ReportBase: def inherited(self) -> str: return "base"
@property def inherited_label(self) -> str: return "base label"
class ReportService(ReportBase): """Generate reports for an application."""
title: str _token: str __secret: str
def __init__(self, title: str = "Sales") -> None: self.title = title self._token = "internal" self.__secret = "private" self.__trace__ = "trace"
def render(self, limit: int = 10) -> str: """Render the report.""" return f"{self.title}: {limit}"
async def refresh(self) -> str: return self.title
def _prepare(self) -> str: return self._token
async def _prepare_async(self) -> str: return self._token
def __sign(self) -> str: return self.__secret
async def __sign_async(self) -> str: return self.__secret
@classmethod def category(cls) -> str: return cls.__name__
@classmethod async def category_async(cls) -> str: return cls.__name__
@classmethod def _category(cls) -> str: return cls.__name__
@classmethod async def _category_async(cls) -> str: return cls.__name__
@classmethod def __category(cls) -> str: return cls.__name__
@classmethod async def __category_async(cls) -> str: return cls.__name__
@staticmethod def valid() -> bool: return True
@staticmethod async def valid_async() -> bool: return True
@staticmethod def _valid() -> bool: return True
@staticmethod async def _valid_async() -> bool: return True
@staticmethod def __valid() -> bool: return True
@staticmethod async def __valid_async() -> bool: return True
@property def label(self) -> str: """Human-readable report label.""" return self.title.upper()
@property def _length(self) -> int: return len(self.title)
@property def __label(self) -> str: return self.__secret
def temporary(self) -> None: return Nonefrom app.services.report_service import ReportServicefrom orionis.introspection import ReflectionInstance
service = ReportService()reflected = ReflectionInstance(service)assert reflected.getInstance() is service__init__
Section titled “__init__”def __init__(self, instance: Any) -> None: ...instance is required and must be an object, not a class. Classes and objects whose instance.__class__.__module__ is builtins or abc raise TypeError; the __main__ module raises ValueError. Importability is not checked: a synthetic class with another module name can also be accepted. The example uses a class defined in an importable file so its source can be retrieved and __main__ is avoided. Construction does not yet scan attributes or methods.
reflected = ReflectionInstance(service)Identity and metadata
Section titled “Identity and metadata”These methods take no arguments. They return references or metadata for the object’s class, not a copy of the service.
getClassName(), getModuleName() and getModuleWithClassName() use names captured when the wrapper is constructed. If you later change the class __name__ or __module__, clearCache() does not refresh those fields; construct another wrapper to obtain the new names.
getInstance
Section titled “getInstance”def getInstance(self) -> Any: ...Return the reflected object itself (Any).
assert reflected.getInstance() is servicegetClass
Section titled “getClass”def getClass(self) -> type: ...Return its class (type).
assert reflected.getClass() is ReportServicegetClassName
Section titled “getClassName”def getClassName(self) -> str: ...Return the class __name__ as str.
assert reflected.getClassName() == "ReportService"getModuleName
Section titled “getModuleName”def getModuleName(self) -> str: ...Return the class module as str.
assert reflected.getModuleName() == "app.services.report_service"getModuleWithClassName
Section titled “getModuleWithClassName”def getModuleWithClassName(self) -> str: ...Join the module and simple class name. Nested classes do not use __qualname__ here.
assert reflected.getModuleWithClassName() == "app.services.report_service.ReportService"getDocstring
Section titled “getDocstring”def getDocstring(self) -> str | None: ...Return the class __doc__, or None; this is not the __init__ docstring.
assert reflected.getDocstring() == "Generate reports for an application."getBaseClasses
Section titled “getBaseClasses”def getBaseClasses(self) -> tuple[type, ...]: ...Return a tuple of direct bases, not the entire MRO hierarchy.
assert reflected.getBaseClasses()[0].__name__ == "ReportBase"getAnnotations
Section titled “getAnnotations”def getAnnotations(self) -> dict[str, type]: ...Return a dictionary of class annotations. Its own private names omit the mangling prefix. This does not infer types from values or convert annotations into resolved dependencies.
assert "title" in reflected.getAnnotations()assert "__secret" in reflected.getAnnotations()getFile
Section titled “getFile”def getFile(self) -> str | None: ...Return the class file path (str), memoized, or None when inspect raises TypeError or OSError.
assert reflected.getFile().endswith("report_service.py")getSourceCode
Section titled “getSourceCode”def getSourceCode(self, method: str | None=None) -> str | None: ...With no method, or an empty value, return the class source. With a name, return source for a method classified in getMethods(), accepting private names such as __sign. Dunder names, including __init__, do not belong to that list and return None when requested individually. Also return None for a missing method or unavailable source (TypeError/OSError). Each variant is memoized.
assert "class ReportService" in reflected.getSourceCode()assert "def render" in reflected.getSourceCode("render")assert "def __sign" in reflected.getSourceCode("__sign")assert reflected.getSourceCode("__init__") is Noneassert reflected.getSourceCode("missing") is NoneObject attributes
Section titled “Object attributes”Scanning uses vars(instance): it enumerates the instance __dict__, without automatically including class variables or computed property values. An object with __slots__ and no __dict__ can be constructed, but these scans raise TypeError.
The dictionaries are cached and returned by reference. Prefixes classify Python names; they do not enforce access control. A private member such as _ReportService__secret appears as __secret; an inherited private member with another class prefix can be classified as protected.
getAttributes
Section titled “getAttributes”def getAttributes(self) -> dict[str, Any]: ...Combine public, protected, own private and dunder entries in dict[str, Any].
assert reflected.getAttributes()["__secret"] == "private"getPublicAttributes
Section titled “getPublicAttributes”def getPublicAttributes(self) -> dict[str, Any]: ...Return entries whose names do not begin with _.
assert reflected.getPublicAttributes() == {"title": "Sales"}getProtectedAttributes
Section titled “getProtectedAttributes”def getProtectedAttributes(self) -> dict[str, Any]: ...Return entries beginning with _ that were not classified as own private or dunder entries.
assert reflected.getProtectedAttributes()["_token"] == "internal"getPrivateAttributes
Section titled “getPrivateAttributes”def getPrivateAttributes(self) -> dict[str, Any]: ...Return own private entries with unmangled names.
assert reflected.getPrivateAttributes()["__secret"] == "private"getDunderAttributes
Section titled “getDunderAttributes”def getDunderAttributes(self) -> dict[str, Any]: ...Return names beginning and ending with __.
assert reflected.getDunderAttributes()["__trace__"] == "trace"getMagicAttributes
Section titled “getMagicAttributes”def getMagicAttributes(self) -> dict[str, Any]: ...Alias of getDunderAttributes(); return the same cached dictionary.
assert reflected.getMagicAttributes() is reflected.getDunderAttributes()hasAttribute
Section titled “hasAttribute”def hasAttribute(self, name: str) -> bool: ...name: str is required. Check the combined dictionary or hasattr(instance, name) and return bool; this can also detect class variables and properties. Dictionary scanning runs first.
assert reflected.hasAttribute("title")assert reflected.hasAttribute("label")assert not reflected.hasAttribute("missing")getAttribute
Section titled “getAttribute”def getAttribute(self, name: str, default: Any=None) -> Any: ...name is required; default=None is used when absent. Prefer the cached dictionary and also evaluate a getattr lookup; that lookup can execute descriptors. Use unmangled names for own private entries. Getter exceptions can propagate.
assert reflected.getAttribute("__secret") == "private"assert reflected.getAttribute("missing", "fallback") == "fallback"assert reflected.getAttribute("label") == "SALES"getAttributeDocstring
Section titled “getAttributeDocstring”def getAttributeDocstring(self, name: str) -> str | None: ...Read the attribute value’s __doc__, or None; this does not extract declaration comments. name is required and accepts own private names. Missing attributes raise AttributeError.
assert reflected.getAttributeDocstring("title") == str.__doc__setAttribute
Section titled “setAttribute”def setAttribute(self, name: str, value: Any) -> bool: ...name and value are required. Require a valid Python identifier that is not a keyword (AttributeError); reject callable values (TypeError). Mangle own private names, call setattr, clear the entire cache and return True. Setter and slot restrictions still apply.
assert reflected.setAttribute("region", "EU") is Trueassert service.region == "EU"assert reflected.setAttribute("__secret", "updated") is Trueassert reflected.getAttribute("__secret") == "updated"removeAttribute
Section titled “removeAttribute”def removeAttribute(self, name: str) -> bool: ...name is required. Delete through delattr, invalidate the cache and return True. Any lookup result equal to None is treated as absent, so an existing attribute set to None also raises AttributeError. Properties without deleters and class-only attributes can fail.
assert reflected.removeAttribute("region") is Trueassert not reflected.hasAttribute("region")Filter methods
Section titled “Filter methods”Scanning traverses dir(type(instance)) using static descriptor access: it includes inherited methods, distinguishes instance functions, classmethod and staticmethod, and separates coroutines with inspect.iscoroutinefunction. It does not invoke methods or property getters. A function returning an awaitable without being a coroutine function remains in the sync filter.
Own private members appear as __sign, without the class prefix. getMethods() excludes dunder names and combines the categories; it is not an execution order. Filters take no arguments and return cached lists of names, not bound methods.
getMethods
Section titled “getMethods”def getMethods(self) -> list[str]: ...All classified methods, excluding dunder names.
assert "render" in reflected.getMethods()assert "inherited" in reflected.getMethods()getDunderMethods
Section titled “getDunderMethods”def getDunderMethods(self) -> list[str]: ...Class dunder names, including inherited names. Scanning collects every __...__ name from dir(cls) before checking callability, so entries such as __module__ can appear.
assert "__init__" in reflected.getDunderMethods()getMagicMethods
Section titled “getMagicMethods”def getMagicMethods(self) -> list[str]: ...Alias of getDunderMethods().
assert reflected.getMagicMethods() is reflected.getDunderMethods()Instance methods
Section titled “Instance methods”getPublicMethods(self) -> list[str] — Return public methods, both sync and async.
assert "render" in reflected.getPublicMethods()getPublicSyncMethods(self) -> list[str] — Return public methods that are synchronous.
assert "render" in reflected.getPublicSyncMethods()getPublicAsyncMethods(self) -> list[str] — Return public methods that are asynchronous.
assert "refresh" in reflected.getPublicAsyncMethods()getProtectedMethods(self) -> list[str] — Return protected methods, both sync and async.
assert "_prepare" in reflected.getProtectedMethods()getProtectedSyncMethods(self) -> list[str] — Return protected methods that are synchronous.
assert "_prepare" in reflected.getProtectedSyncMethods()getProtectedAsyncMethods(self) -> list[str] — Return protected methods that are asynchronous.
assert "_prepare_async" in reflected.getProtectedAsyncMethods()getPrivateMethods(self) -> list[str] — Return own private methods, both sync and async.
assert "__sign" in reflected.getPrivateMethods()getPrivateSyncMethods(self) -> list[str] — Return own private methods that are synchronous.
assert "__sign" in reflected.getPrivateSyncMethods()getPrivateAsyncMethods(self) -> list[str] — Return own private methods that are asynchronous.
assert "__sign_async" in reflected.getPrivateAsyncMethods()Class methods
Section titled “Class methods”getPublicClassMethods(self) -> list[str] — Return public methods, both sync and async.
assert "category" in reflected.getPublicClassMethods()getPublicClassSyncMethods(self) -> list[str] — Return public methods that are synchronous.
assert "category" in reflected.getPublicClassSyncMethods()getPublicClassAsyncMethods(self) -> list[str] — Return public methods that are asynchronous.
assert "category_async" in reflected.getPublicClassAsyncMethods()getProtectedClassMethods(self) -> list[str] — Return protected methods, both sync and async.
assert "_category" in reflected.getProtectedClassMethods()getProtectedClassSyncMethods(self) -> list[str] — Return protected methods that are synchronous.
assert "_category" in reflected.getProtectedClassSyncMethods()getProtectedClassAsyncMethods(self) -> list[str] — Return protected methods that are asynchronous.
assert "_category_async" in reflected.getProtectedClassAsyncMethods()getPrivateClassMethods(self) -> list[str] — Return own private methods, both sync and async.
assert "__category" in reflected.getPrivateClassMethods()getPrivateClassSyncMethods(self) -> list[str] — Return own private methods that are synchronous.
assert "__category" in reflected.getPrivateClassSyncMethods()getPrivateClassAsyncMethods(self) -> list[str] — Return own private methods that are asynchronous.
assert "__category_async" in reflected.getPrivateClassAsyncMethods()Static methods
Section titled “Static methods”getPublicStaticMethods(self) -> list[str] — Return public methods, both sync and async.
assert "valid" in reflected.getPublicStaticMethods()getPublicStaticSyncMethods(self) -> list[str] — Return public methods that are synchronous.
assert "valid" in reflected.getPublicStaticSyncMethods()getPublicStaticAsyncMethods(self) -> list[str] — Return public methods that are asynchronous.
assert "valid_async" in reflected.getPublicStaticAsyncMethods()getProtectedStaticMethods(self) -> list[str] — Return protected methods, both sync and async.
assert "_valid" in reflected.getProtectedStaticMethods()getProtectedStaticSyncMethods(self) -> list[str] — Return protected methods that are synchronous.
assert "_valid" in reflected.getProtectedStaticSyncMethods()getProtectedStaticAsyncMethods(self) -> list[str] — Return protected methods that are asynchronous.
assert "_valid_async" in reflected.getProtectedStaticAsyncMethods()getPrivateStaticMethods(self) -> list[str] — Return own private methods, both sync and async.
assert "__valid" in reflected.getPrivateStaticMethods()getPrivateStaticSyncMethods(self) -> list[str] — Return own private methods that are synchronous.
assert "__valid" in reflected.getPrivateStaticSyncMethods()getPrivateStaticAsyncMethods(self) -> list[str] — Return own private methods that are asynchronous.
assert "__valid_async" in reflected.getPrivateStaticAsyncMethods()Method signatures and editing
Section titled “Method signatures and editing”hasMethod
Section titled “hasMethod”def hasMethod(self, name: str) -> bool: ...Check whether required name belongs to the classified class method set. This does not inspect instance-only attached callables or include dunder names.
assert reflected.hasMethod("render")assert reflected.hasMethod("__sign")assert not reflected.hasMethod("__init__")getMethodSignature
Section titled “getMethodSignature”def getMethodSignature(self, name: str) -> inspect.Signature: ...With required name, return an inspect.Signature for a callable class member, mangling own private names. Dunder names such as __init__ are supported independently of hasMethod(). An instance method retains self in this signature; a classmethod already bound to its class does not retain cls. Non-callables raise AttributeError; inspection errors propagate.
assert list(reflected.getMethodSignature("render").parameters) == ["self", "limit"]assert list(reflected.getMethodSignature("__init__").parameters) == ["self", "title"]assert list(reflected.getMethodSignature("__sign").parameters) == ["self"]getMethodDocstring
Section titled “getMethodDocstring”def getMethodDocstring(self, name: str) -> str | None: ...With required name, return the class callable docstring, or None. Own private names are supported and results are memoized. Missing or non-callable members raise AttributeError.
assert reflected.getMethodDocstring("render") == "Render the report."setMethod
Section titled “setMethod”def setMethod(self, name: str, method: Callable) -> bool: ...name and method: Callable are required. Validate the name as in setAttribute, require a callable (TypeError), assign it to the object and return True, clearing the cache. This neither binds self automatically nor adds it to class filters. Use types.MethodType when the function expects an instance.
from types import MethodType
assert reflected.setMethod("extra", lambda: "ready") is Trueassert service.extra() == "ready"assert not reflected.hasMethod("extra")
def describe(instance): return instance.title
reflected.setMethod("describe", MethodType(describe, service))assert service.describe() == "Sales"removeMethod
Section titled “removeMethod”def removeMethod(self, name: str) -> None: ...With required name, first require hasMethod() to be true, then delete the class member, not the instance member. Return None; this affects every instance of that class. Missing members raise AttributeError. It cannot remove a merely inherited method from a subclass. Use it for directly declared public or protected methods: ordinary private methods cannot be removed through this API because lookup and deletion do not apply the same mangling rules. Both __secret and _Class__secret raise AttributeError in that case.
assert reflected.removeMethod("temporary") is Noneassert not hasattr(service, "temporary")constructorSignature
Section titled “constructorSignature”def constructorSignature(self) -> Signature: ...With no arguments, return an Orionis Signature for __init__. Its resolved, unresolved and ordered maps contain Argument objects; they are not constructed services. Results are memoized. See the dependencies guide for the complete classification.
dependencies = reflected.constructorSignature()assert list(dependencies.ordered) == ["title"]assert "title" in dependencies.resolvedmethodSignature
Section titled “methodSignature”def methodSignature(self, method_name: str) -> Signature: ...With required method_name, return an Orionis Signature for the method bound to the object, omitting self. Check hasMethod(), support own private names and memoize by name. Unclassified methods raise AttributeError. This does not call the container or execute the method.
dependencies = reflected.methodSignature("render")assert list(dependencies.ordered) == ["limit"]assert "limit" in dependencies.resolvedProperties
Section titled “Properties”Enumerating property descriptors scans only ReportService.__dict__: inherited properties and dunder names __...__ are omitted. Scanning does not execute getters. Signature and docstring lookups use getattr on the class and can find inherited property descriptors; getProperty() requires membership in the directly declared property list.
getProperties
Section titled “getProperties”def getProperties(self) -> list[str]: ...Return list[str] of directly declared properties of every visibility.
assert reflected.getProperties() == ["label", "_length", "__label"]assert "inherited_label" not in reflected.getProperties()getPublicProperties
Section titled “getPublicProperties”def getPublicProperties(self) -> list: ...Return a list of directly declared public property names.
assert reflected.getPublicProperties() == ["label"]getProtectedProperties
Section titled “getProtectedProperties”def getProtectedProperties(self) -> list: ...Return a list of directly declared protected property names.
assert reflected.getProtectedProperties() == ["_length"]getPrivateProperties
Section titled “getPrivateProperties”def getPrivateProperties(self) -> list: ...Return a list of unmangled, directly declared private property names.
assert reflected.getPrivateProperties() == ["__label"]getProperty
Section titled “getProperty”def getProperty(self, name: str) -> Any: ...name is required. Execute the getter and return its value (Any). Own private names are supported; a property outside the list raises AttributeError. Getter exceptions propagate.
assert reflected.getProperty("label") == "SALES"assert reflected.getProperty("__label") == "updated"getPropertySignature
Section titled “getPropertySignature”def getPropertySignature(self, name: str) -> inspect.Signature: ...name is required. Return the getter fget inspect.Signature, including self, without executing it. Results are memoized; own private names are supported and non-property members raise AttributeError. A descriptor without a getter cannot normally be inspected.
assert list(reflected.getPropertySignature("label").parameters) == ["self"]getPropertyDocstring
Section titled “getPropertyDocstring”def getPropertyDocstring(self, name: str) -> str: ...name is required. Return the getter docstring as str, or "" when undocumented. Results are memoized and own private names are supported. Non-property members raise AttributeError.
assert reflected.getPropertyDocstring("label") == "Human-readable report label."assert reflected.getPropertyDocstring("_length") == ""Local cache and dictionary protocol
Section titled “Local cache and dictionary protocol”Collections and signatures are memoized snapshots per wrapper. External object or class changes do not refresh results automatically. This wrapper’s write operations clear its own cache; other wrappers for the same object retain their snapshots. Nothing is written to disk.
clearCache
Section titled “clearCache”def clearCache(self) -> None: ...Remove all entries and return None; subsequent access scans members again.
reflected.getAttributes()service.title = "Revenue"assert reflected.getAttribute("title") == "Sales"reflected.clearCache()assert reflected.getAttribute("title") == "Revenue"__setitem__
Section titled “__setitem__”def __setitem__(self, key: str, value: object) -> None: ...Store value under key in the cache and return None.
reflected["custom:note"] = "diagnostic"__getitem__
Section titled “__getitem__”def __getitem__(self, key: str) -> object | None: ...Return an entry, or None when absent; this does not raise KeyError.
assert reflected["custom:note"] == "diagnostic"assert reflected["custom:missing"] is None__contains__
Section titled “__contains__”def __contains__(self, key: str) -> bool: ...Test cache key membership, not object attribute existence.
assert "custom:note" in reflected__delitem__
Section titled “__delitem__”def __delitem__(self, key: str) -> None: ...Remove an entry when present; absent keys do not fail. Return None.
del reflected["custom:note"]del reflected["custom:missing"]Use your own prefixes for auxiliary entries: writing internal keys such as attributes or methods changes wrapper reads.
Dependency injection
Section titled “Dependency injection”Do not register a generic wrapper without specifying its target object. In a controller or another Orionis-resolved component, inject the actual service and construct reflection around that instance. Reflection annotations describe dependencies; they do not inject them themselves.
from app.services.report_service import ReportServicefrom orionis.http import JSONResponsefrom orionis.introspection import ReflectionInstance
class DiagnosticsController: async def __call__(self, reports: ReportService) -> JSONResponse: reflected = ReflectionInstance(reports) return JSONResponse({ "class": reflected.getModuleWithClassName(), "methods": reflected.getPublicMethods(), })The wrapper contract is IReflectionInstance, importable from orionis.introspection.instances.contracts.reflection. It does not remove the need to specify the target object: injecting a particular wrapper requires an instance or factory configured for that target through your provider.