Mejora del motor de evaluación con la adición de funciones de plotting y compatibilidad con tipos SymPy en las clases IP4 y FourBytes. Se actualiza el contexto base para incluir nuevas funciones matemáticas y se implementa la verificación de clases requeridas en el contexto. Se optimiza el manejo de errores y se mejora la conversión de tipos SymPy a nativos.
This commit is contained in:
parent
7d2033c60e
commit
556c63ad31
|
@ -24,6 +24,7 @@ class FourBytes(ClassBase):
|
|||
# Modo algebraico: mantener símbolos INTERNAMENTE, no convertir a SymPy aún
|
||||
self._symbols = self._extract_symbols()
|
||||
self._numeric_value = None # No hay valor numérico directo
|
||||
self._symbolic_value = self.to_sympy() # AÑADIDO: compatibilidad con IP4
|
||||
super().__init__(self.original, self.original) # ClassBase, NO SympyClassBase
|
||||
else:
|
||||
# Modo numérico: validar rangos y convertir
|
||||
|
@ -43,6 +44,7 @@ class FourBytes(ClassBase):
|
|||
self._numeric_elements[2] << 8 |
|
||||
self._numeric_elements[3])
|
||||
self._symbols = []
|
||||
self._symbolic_value = self._numeric_value # AÑADIDO: compatibilidad con IP4
|
||||
super().__init__(self._numeric_value, self.original) # ClassBase
|
||||
|
||||
def _extract_symbols(self):
|
||||
|
|
|
@ -59,6 +59,14 @@ class IP4Mask(ClassBase):
|
|||
def _parse_mask(self, mask_input: Union[int, str]) -> int:
|
||||
"""Helper to parse mask_input and return prefix."""
|
||||
prefix_val: int
|
||||
|
||||
# Manejar tipos SymPy (convirtiendo a int nativo)
|
||||
if hasattr(mask_input, '__int__'): # SymPy Integer, etc.
|
||||
try:
|
||||
mask_input = int(mask_input)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if isinstance(mask_input, int):
|
||||
if not (0 <= mask_input <= 32):
|
||||
raise ValueError(f"Invalid prefix length: {mask_input}. Must be between 0 and 32.")
|
||||
|
@ -361,7 +369,16 @@ class Class_IP4(SympyClassBase):
|
|||
# Obtener clases dinámicamente
|
||||
IntBase, FourBytes = get_base_classes()
|
||||
|
||||
# Procesar dirección
|
||||
# Procesar dirección (con compatibilidad SymPy)
|
||||
|
||||
# Convertir objetos SymPy de vuelta a strings si es necesario
|
||||
if hasattr(address, '__str__') and not isinstance(address, (str, int, float)):
|
||||
# Probablemente es un objeto SymPy - convertir a string
|
||||
address_str = str(address)
|
||||
if '.' in address_str and len(address_str.split('.')) == 4:
|
||||
# Parece una IP, usar el string
|
||||
address = address_str
|
||||
|
||||
if FourBytes and isinstance(address, FourBytes):
|
||||
# address es FourBytes (ya tokenizado desde x.x.x.x)
|
||||
self.address = address
|
||||
|
@ -407,12 +424,39 @@ class Class_IP4(SympyClassBase):
|
|||
else:
|
||||
self._ip_int = self.address._numeric_value
|
||||
self._has_symbols = False
|
||||
|
||||
elif hasattr(address, '__int__'): # SymPy Integer u otros números
|
||||
# Convertir número a IP string (asumiendo formato de 32 bits)
|
||||
try:
|
||||
addr_int = int(address)
|
||||
self._ip_str = f"{(addr_int >> 24) & 0xFF}.{(addr_int >> 16) & 0xFF}.{(addr_int >> 8) & 0xFF}.{addr_int & 0xFF}"
|
||||
|
||||
if FourBytes:
|
||||
self.address = FourBytes(self._ip_str)
|
||||
else:
|
||||
self.address = type('MockFourBytes', (), {
|
||||
'original': self._ip_str,
|
||||
'has_symbols': False,
|
||||
'_numeric_value': addr_int
|
||||
})()
|
||||
|
||||
self._ip_int = addr_int
|
||||
self._has_symbols = False
|
||||
except (ValueError, TypeError):
|
||||
raise TypeError(f"No se pudo convertir {address} (tipo: {type(address)}) a dirección IP")
|
||||
|
||||
else:
|
||||
raise TypeError(f"address debe ser FourBytes o string, recibido: {type(address)}")
|
||||
raise TypeError(f"address debe ser FourBytes, string, o número, recibido: {type(address)}")
|
||||
|
||||
# Procesar máscara
|
||||
if mask is not None:
|
||||
# Convertir tipos SymPy a tipos nativos
|
||||
if hasattr(mask, '__int__'): # SymPy Integer, etc.
|
||||
try:
|
||||
mask = int(mask)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if isinstance(mask, IP4Mask):
|
||||
self._mask_obj = mask
|
||||
elif isinstance(mask, (int, str)):
|
||||
|
@ -424,7 +468,7 @@ class Class_IP4(SympyClassBase):
|
|||
# Máscara desde hex (ej: 16#ffffff00)
|
||||
self._mask_obj = IP4Mask(mask)
|
||||
else:
|
||||
raise TypeError(f"mask debe ser int, str, IP4Mask, FourBytes, o IntBase")
|
||||
raise TypeError(f"mask debe ser int, str, IP4Mask, FourBytes, o IntBase, recibido: {type(mask)}")
|
||||
else:
|
||||
self._mask_obj = None
|
||||
|
||||
|
|
|
@ -61,9 +61,11 @@ class PureAlgebraicEngine:
|
|||
def _load_base_context(self):
|
||||
"""Carga el contexto base con funciones y tipos"""
|
||||
try:
|
||||
# Contexto de SymPy
|
||||
# Contexto de SymPy básico
|
||||
self.context.update({
|
||||
'sin': sp.sin, 'cos': sp.cos, 'tan': sp.tan,
|
||||
'asin': sp.asin, 'acos': sp.acos, 'atan': sp.atan,
|
||||
'sinh': sp.sinh, 'cosh': sp.cosh, 'tanh': sp.tanh,
|
||||
'log': sp.log, 'ln': sp.ln, 'exp': sp.exp,
|
||||
'sqrt': sp.sqrt, 'abs': sp.Abs,
|
||||
'pi': sp.pi, 'e': sp.E, 'I': sp.I,
|
||||
|
@ -73,12 +75,43 @@ class PureAlgebraicEngine:
|
|||
'expand': sp.expand, 'factor': sp.factor,
|
||||
'diff': sp.diff, 'integrate': sp.integrate,
|
||||
'Matrix': sp.Matrix, 'symbols': sp.symbols,
|
||||
'Symbol': sp.Symbol, 'Rational': sp.Rational,
|
||||
'Float': sp.Float, 'Integer': sp.Integer,
|
||||
'limit': sp.limit, 'series': sp.series,
|
||||
'summation': sp.summation, 'product': sp.product,
|
||||
'binomial': sp.binomial, 'factorial': sp.factorial,
|
||||
'gcd': sp.gcd, 'lcm': sp.lcm,
|
||||
'ceiling': sp.ceiling, 'floor': sp.floor,
|
||||
'Piecewise': sp.Piecewise,
|
||||
})
|
||||
|
||||
# Funciones de plotting
|
||||
try:
|
||||
from sympy.plotting import plot, plot3d, plot_parametric, plot3d_parametric_line
|
||||
self.context.update({
|
||||
'plot': plot,
|
||||
'plot3d': plot3d,
|
||||
'plot_parametric': plot_parametric,
|
||||
'plot3d_parametric_line': plot3d_parametric_line,
|
||||
})
|
||||
self.logger.debug("Funciones de plotting cargadas")
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Error cargando funciones de plotting: {e}")
|
||||
|
||||
# Contexto dinámico de tipos personalizados
|
||||
dynamic_context = get_registered_base_context()
|
||||
self.context.update(dynamic_context)
|
||||
|
||||
# Verificar que las clases principales estén disponibles
|
||||
required_classes = ['IP4', 'IP4Mask', 'FourBytes', 'IntBase', 'Hex', 'Bin', 'Dec', 'Chr', 'LaTeX']
|
||||
missing_classes = []
|
||||
for cls_name in required_classes:
|
||||
if cls_name not in self.context:
|
||||
missing_classes.append(cls_name)
|
||||
|
||||
if missing_classes:
|
||||
self.logger.warning(f"Clases faltantes en contexto: {missing_classes}")
|
||||
|
||||
self.logger.debug(f"Contexto cargado: {len(self.context)} elementos")
|
||||
|
||||
except Exception as e:
|
||||
|
|
Loading…
Reference in New Issue