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
|
# Modo algebraico: mantener símbolos INTERNAMENTE, no convertir a SymPy aún
|
||||||
self._symbols = self._extract_symbols()
|
self._symbols = self._extract_symbols()
|
||||||
self._numeric_value = None # No hay valor numérico directo
|
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
|
super().__init__(self.original, self.original) # ClassBase, NO SympyClassBase
|
||||||
else:
|
else:
|
||||||
# Modo numérico: validar rangos y convertir
|
# Modo numérico: validar rangos y convertir
|
||||||
|
@ -43,6 +44,7 @@ class FourBytes(ClassBase):
|
||||||
self._numeric_elements[2] << 8 |
|
self._numeric_elements[2] << 8 |
|
||||||
self._numeric_elements[3])
|
self._numeric_elements[3])
|
||||||
self._symbols = []
|
self._symbols = []
|
||||||
|
self._symbolic_value = self._numeric_value # AÑADIDO: compatibilidad con IP4
|
||||||
super().__init__(self._numeric_value, self.original) # ClassBase
|
super().__init__(self._numeric_value, self.original) # ClassBase
|
||||||
|
|
||||||
def _extract_symbols(self):
|
def _extract_symbols(self):
|
||||||
|
|
|
@ -59,6 +59,14 @@ class IP4Mask(ClassBase):
|
||||||
def _parse_mask(self, mask_input: Union[int, str]) -> int:
|
def _parse_mask(self, mask_input: Union[int, str]) -> int:
|
||||||
"""Helper to parse mask_input and return prefix."""
|
"""Helper to parse mask_input and return prefix."""
|
||||||
prefix_val: int
|
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 isinstance(mask_input, int):
|
||||||
if not (0 <= mask_input <= 32):
|
if not (0 <= mask_input <= 32):
|
||||||
raise ValueError(f"Invalid prefix length: {mask_input}. Must be between 0 and 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
|
# Obtener clases dinámicamente
|
||||||
IntBase, FourBytes = get_base_classes()
|
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):
|
if FourBytes and isinstance(address, FourBytes):
|
||||||
# address es FourBytes (ya tokenizado desde x.x.x.x)
|
# address es FourBytes (ya tokenizado desde x.x.x.x)
|
||||||
self.address = address
|
self.address = address
|
||||||
|
@ -408,11 +425,38 @@ class Class_IP4(SympyClassBase):
|
||||||
self._ip_int = self.address._numeric_value
|
self._ip_int = self.address._numeric_value
|
||||||
self._has_symbols = False
|
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:
|
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
|
# Procesar máscara
|
||||||
if mask is not None:
|
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):
|
if isinstance(mask, IP4Mask):
|
||||||
self._mask_obj = mask
|
self._mask_obj = mask
|
||||||
elif isinstance(mask, (int, str)):
|
elif isinstance(mask, (int, str)):
|
||||||
|
@ -424,7 +468,7 @@ class Class_IP4(SympyClassBase):
|
||||||
# Máscara desde hex (ej: 16#ffffff00)
|
# Máscara desde hex (ej: 16#ffffff00)
|
||||||
self._mask_obj = IP4Mask(mask)
|
self._mask_obj = IP4Mask(mask)
|
||||||
else:
|
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:
|
else:
|
||||||
self._mask_obj = None
|
self._mask_obj = None
|
||||||
|
|
||||||
|
|
|
@ -61,9 +61,11 @@ class PureAlgebraicEngine:
|
||||||
def _load_base_context(self):
|
def _load_base_context(self):
|
||||||
"""Carga el contexto base con funciones y tipos"""
|
"""Carga el contexto base con funciones y tipos"""
|
||||||
try:
|
try:
|
||||||
# Contexto de SymPy
|
# Contexto de SymPy básico
|
||||||
self.context.update({
|
self.context.update({
|
||||||
'sin': sp.sin, 'cos': sp.cos, 'tan': sp.tan,
|
'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,
|
'log': sp.log, 'ln': sp.ln, 'exp': sp.exp,
|
||||||
'sqrt': sp.sqrt, 'abs': sp.Abs,
|
'sqrt': sp.sqrt, 'abs': sp.Abs,
|
||||||
'pi': sp.pi, 'e': sp.E, 'I': sp.I,
|
'pi': sp.pi, 'e': sp.E, 'I': sp.I,
|
||||||
|
@ -73,12 +75,43 @@ class PureAlgebraicEngine:
|
||||||
'expand': sp.expand, 'factor': sp.factor,
|
'expand': sp.expand, 'factor': sp.factor,
|
||||||
'diff': sp.diff, 'integrate': sp.integrate,
|
'diff': sp.diff, 'integrate': sp.integrate,
|
||||||
'Matrix': sp.Matrix, 'symbols': sp.symbols,
|
'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
|
# Contexto dinámico de tipos personalizados
|
||||||
dynamic_context = get_registered_base_context()
|
dynamic_context = get_registered_base_context()
|
||||||
self.context.update(dynamic_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")
|
self.logger.debug(f"Contexto cargado: {len(self.context)} elementos")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
Loading…
Reference in New Issue