Ir al contenido

Clases Concretas

La clase ReflectionConcrete es una utilidad avanzada de introspección diseñada para analizar clases concretas de Python en tiempo de ejecución. Proporciona una API completa para inspeccionar atributos, métodos, propiedades, metadatos y dependencias de cualquier clase concreta (no abstracta) registrada en el framework Orionis.

A diferencia de ReflectionAbstract, que opera sobre clases base abstractas, ReflectionConcrete se enfoca exclusivamente en clases instanciables que tienen una implementación completa. Esto la convierte en la herramienta ideal para el análisis de servicios, controladores, modelos y cualquier componente concreto del framework.

from orionis.services.introspection.concretes.reflection import ReflectionConcrete

La clase ReflectionConcrete recibe como parámetro una clase concreta válida. Si la clase proporcionada es abstracta, un tipo primitivo, un built-in o no es una clase, se lanzará un TypeError.

from orionis.services.introspection.concretes.reflection import ReflectionConcrete
class UserService:
"""Service for managing users."""
active: bool = True
def __init__(self, name: str = "default") -> None:
self.name = name
def greet(self) -> str:
return f"Hello, {self.name}"
reflection = ReflectionConcrete(UserService)

Si intentas pasar un tipo no válido:

from abc import ABC, abstractmethod
class MyContract(ABC):
@abstractmethod
def execute(self) -> str: ...
# TypeError: clase abstracta
ReflectionConcrete(MyContract)
# TypeError: no es una clase
ReflectionConcrete(42)
# TypeError: built-in
ReflectionConcrete(len)

La clase ReflectionConcrete implementa el contrato IReflectionConcrete, que define la interfaz completa para la introspección de clases concretas:

from orionis.services.introspection.concretes.contracts.reflection import IReflectionConcrete

Estos métodos permiten obtener información básica de identificación sobre la clase reflejada.

Retorna el tipo (la clase) asociado a la instancia de reflexión.

cls = reflection.getClass()
# <class 'UserService'>

Retorna el nombre simple de la clase como cadena de texto.

name = reflection.getClassName()
# "UserService"

Retorna el nombre del módulo donde está definida la clase.

module = reflection.getModuleName()
# "app.services.user_service"

Retorna el nombre completamente cualificado (módulo + clase).

fqn = reflection.getModuleWithClassName()
# "app.services.user_service.UserService"

Retorna el docstring de la clase, o None si no tiene.

doc = reflection.getDocstring()
# "Service for managing users."

Retorna la lista de clases base directas en el orden de resolución.

bases = reflection.getBaseClasses()
# [<class 'object'>]

Retorna el código fuente de la clase completa o de un método específico. Retorna None si el código no está disponible.

# Código fuente de toda la clase
source = reflection.getSourceCode()
# Código fuente de un método específico
method_source = reflection.getSourceCode("greet")

Para métodos privados con name mangling, utiliza el nombre sin prefijo:

source = reflection.getSourceCode("__private_method")

Retorna la ruta absoluta del archivo donde está definida la clase.

path = reflection.getFile()
# "/app/services/user_service.py"

Retorna un diccionario con las anotaciones de tipo de la clase. Resuelve automáticamente el name mangling en atributos privados.

annotations = reflection.getAnnotations()
# {"active": <class 'bool'>}

ReflectionConcrete clasifica los atributos de la clase por nivel de visibilidad, excluyendo métodos, propiedades, staticmethod y classmethod.

Retorna todos los atributos de la clase, combinando públicos, protegidos, privados y dunder.

attrs = reflection.getAttributes()

Retorna los atributos públicos (sin prefijo de guión bajo).

public = reflection.getPublicAttributes()
# {"active": True}

Retorna los atributos protegidos (prefijo _).

protected = reflection.getProtectedAttributes()
# {"_internal_flag": False}

Retorna los atributos privados (prefijo __). Los nombres se devuelven sin name mangling.

private = reflection.getPrivateAttributes()
# {"__secret": "value"} — no "_ClassName__secret"

Retorna los atributos dunder personalizados de la clase, excluyendo los estándar de Python (__dict__, __module__, __doc__, etc.). getMagicAttributes es un alias de getDunderAttributes.

dunder = reflection.getDunderAttributes()
magic = reflection.getMagicAttributes() # Equivalente

Verifica si un atributo existe en la clase.

reflection.hasAttribute("active") # True
reflection.hasAttribute("missing") # False

Obtiene el valor de un atributo, con soporte para valor por defecto.

value = reflection.getAttribute("active") # True
value = reflection.getAttribute("missing", "N/A") # "N/A"

Establece un atributo en la clase. Solo valores no invocables son aceptados; para agregar métodos, utiliza setMethod.

reflection.setAttribute("active", False) # True

Validaciones:

  • El nombre debe ser un identificador Python válido
  • No puede ser una palabra reservada
  • El valor no puede ser un callable (lanza TypeError)

Elimina un atributo de la clase. Lanza ValueError si el atributo no existe.

reflection.removeAttribute("active") # True

ReflectionConcrete ofrece una API granular para inspeccionar métodos organizados por tres ejes: visibilidad (público, protegido, privado), tipo (instancia, clase, estático, dunder) y naturaleza (síncrono, asíncrono).

MétodoDescripción
getMethods()Todos los métodos (instancia + clase + estáticos)
getPublicMethods()Métodos de instancia públicos
getPublicSyncMethods()Públicos síncronos
getPublicAsyncMethods()Públicos asíncronos
getProtectedMethods()Métodos de instancia protegidos (_)
getProtectedSyncMethods()Protegidos síncronos
getProtectedAsyncMethods()Protegidos asíncronos
getPrivateMethods()Métodos de instancia privados (__)
getPrivateSyncMethods()Privados síncronos
getPrivateAsyncMethods()Privados asíncronos
getPublicClassMethods()Class methods públicos
getPublicClassSyncMethods()Class methods públicos síncronos
getPublicClassAsyncMethods()Class methods públicos asíncronos
getProtectedClassMethods()Class methods protegidos
getProtectedClassSyncMethods()Class methods protegidos síncronos
getProtectedClassAsyncMethods()Class methods protegidos asíncronos
getPrivateClassMethods()Class methods privados
getPrivateClassSyncMethods()Class methods privados síncronos
getPrivateClassAsyncMethods()Class methods privados asíncronos
getPublicStaticMethods()Static methods públicos
getPublicStaticSyncMethods()Static methods públicos síncronos
getPublicStaticAsyncMethods()Static methods públicos asíncronos
getProtectedStaticMethods()Static methods protegidos
getProtectedStaticSyncMethods()Static methods protegidos síncronos
getProtectedStaticAsyncMethods()Static methods protegidos asíncronos
getPrivateStaticMethods()Static methods privados
getPrivateStaticSyncMethods()Static methods privados síncronos
getPrivateStaticAsyncMethods()Static methods privados asíncronos
getDunderMethods()Métodos dunder (__init__, __repr__, etc.)
getMagicMethods()Alias de getDunderMethods()

Todos los métodos retornan list[str] con los nombres de los métodos encontrados. Los métodos privados se retornan sin name mangling.

class MyService:
def process(self) -> str:
return "done"
async def fetch(self) -> dict:
return {}
def _validate(self) -> bool:
return True
@classmethod
def create(cls) -> "MyService":
return cls()
@staticmethod
def version() -> str:
return "1.0"
reflection = ReflectionConcrete(MyService)
reflection.getPublicMethods() # ["process", "fetch"]
reflection.getPublicSyncMethods() # ["process"]
reflection.getPublicAsyncMethods() # ["fetch"]
reflection.getProtectedMethods() # ["_validate"]
reflection.getPublicClassMethods() # ["create"]
reflection.getPublicStaticMethods() # ["version"]

Verifica si un método existe en la clase (busca en todas las categorías).

reflection.hasMethod("process") # True
reflection.hasMethod("missing") # False

Agrega un nuevo método a la clase. Lanza ValueError si el nombre ya existe o es inválido, y TypeError si el valor no es callable.

def new_method(self) -> str:
return "new"
reflection.setMethod("new_method", new_method) # True

Elimina un método de la clase. Lanza ValueError si el método no existe.

reflection.removeMethod("new_method") # True

Retorna el objeto inspect.Signature de un método específico.

sig = reflection.getMethodSignature("process")
# (self) -> str

Retorna los nombres de todas las propiedades definidas en la clase.

class Config:
@property
def host(self) -> str:
"""Server hostname."""
return "localhost"
@property
def _port(self) -> int:
return 8080
reflection = ReflectionConcrete(Config)
reflection.getProperties() # ["host", "_port"]
MétodoDescripción
getPublicProperties()Propiedades públicas
getProtectedProperties()Propiedades protegidas (_)
getPrivateProperties()Propiedades privadas (__, sin mangling)

Obtiene el valor de una propiedad ejecutando su getter. Lanza ValueError si no existe o TypeError si no es una propiedad.

value = reflection.getProperty("host") # "localhost"

Retorna la firma del getter de una propiedad.

sig = reflection.getPropertySignature("host")
# (self) -> str

Retorna el docstring del getter de una propiedad, o None si no tiene.

doc = reflection.getPropertyDocstring("host")
# "Server hostname."

Retorna el objeto inspect.Signature del método __init__.

sig = reflection.getConstructorSignature()
# (self, name: str = 'default') -> None

Analiza las dependencias del constructor, identificando parámetros resueltos (con valor por defecto o tipo primitivo) y no resueltos (que requieren inyección de dependencias).

analysis = reflection.constructorSignature()
# Signature(resolved=[...], unresolved=[...])

Analiza las dependencias de un método específico. Lanza AttributeError si el método no existe.

analysis = reflection.methodSignature("process")
# Signature(resolved=[...], unresolved=[...])

ReflectionConcrete implementa un sistema de caché en memoria que almacena los resultados de las operaciones de introspección. Esto evita recalcular resultados costosos en llamadas repetidas.

La instancia soporta acceso tipo diccionario para el caché:

# Verificar existencia
"key" in reflection
# Obtener valor (None si no existe)
reflection["key"]
# Establecer valor
reflection["key"] = value
# Eliminar entrada
del reflection["key"]

Limpia todas las entradas del caché. Las siguientes llamadas a métodos recalcularán sus resultados.

reflection.clearCache()