"""
Actualización de la clase IP4Mask con nuevos métodos para obtener la máscara y el conteo de hosts disponibles. Se mejora la integración con la clase Class_IP4 y se ajusta el autocompletado en la aplicación principal. Se modifica la configuración de la ventana y se añaden sugerencias contextuales para el autocompletado. """
This commit is contained in:
parent
23676b9ef9
commit
036eeb4291
|
@ -0,0 +1,38 @@
|
|||
import sympy
|
||||
|
||||
class ClassBase:
|
||||
"""Clase base para todas las clases del sistema"""
|
||||
|
||||
def __init__(self, value, original_str=""):
|
||||
self._value = value
|
||||
self._original_str = original_str
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self._value
|
||||
|
||||
@property
|
||||
def original_str(self):
|
||||
return self._original_str
|
||||
|
||||
# Sistema de ayuda y autocompletado
|
||||
@staticmethod
|
||||
def Helper(input_str):
|
||||
"""Override en subclases"""
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def PopupFunctionList():
|
||||
"""Override en subclases"""
|
||||
return []
|
||||
|
||||
# Métodos básicos comunes
|
||||
def __str__(self):
|
||||
return str(self._value)
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.__class__.__name__}('{self._original_str}')"
|
||||
|
||||
# Necesitaremos importar sympy en los archivos que usen SympyClassBase.
|
||||
# sympy.sympify también se menciona.
|
||||
# from sympy import sympify (si es necesario globalmente aquí o en las clases hijas)
|
|
@ -12,6 +12,12 @@ Hex[ff]
|
|||
|
||||
Hex[ff].toDecimal()
|
||||
|
||||
IP4[110.1.30.70,255.255.255.0]
|
||||
n=IP4[110.1.30.70;255.255.255.0]
|
||||
|
||||
IP4[110.1.30.70,255.255.255.0]
|
||||
n.mask()
|
||||
|
||||
m=IP4Mask[23]
|
||||
|
||||
IP4Mask[22]
|
||||
|
||||
IP4[110.1.30.70;255.255.255.0]
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"window_geometry": "1020x700+2638+160",
|
||||
"sash_pos_x": 303
|
||||
"sash_pos_x": 332
|
||||
}
|
149
ip4_type.py
149
ip4_type.py
|
@ -1,11 +1,13 @@
|
|||
"""
|
||||
Clase híbrida para direcciones IPv4
|
||||
"""
|
||||
from class_base import ClassBase
|
||||
from sympy_Base import SympyClassBase
|
||||
from typing import Optional, Union
|
||||
import re
|
||||
import sympy
|
||||
|
||||
class IP4Mask:
|
||||
class IP4Mask(ClassBase):
|
||||
"""
|
||||
Helper class to manage IPv4 masks.
|
||||
It can be initialized with an integer prefix (0-32) or a netmask string (e.g., "255.255.255.0").
|
||||
|
@ -14,27 +16,32 @@ class IP4Mask:
|
|||
_mask_int: int
|
||||
|
||||
def __init__(self, mask_input: Union[int, str]):
|
||||
prefix = self._parse_mask(mask_input)
|
||||
super().__init__(prefix, str(mask_input))
|
||||
self._prefix = prefix
|
||||
self._mask_int = self._prefix_to_mask_int(self._prefix)
|
||||
|
||||
def _parse_mask(self, mask_input: Union[int, str]) -> int:
|
||||
"""Helper to parse mask_input and return prefix."""
|
||||
prefix_val: int
|
||||
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.")
|
||||
self._prefix = mask_input
|
||||
prefix_val = mask_input
|
||||
elif isinstance(mask_input, str):
|
||||
try:
|
||||
# Try to interpret as prefix length string, e.g., "24"
|
||||
prefix_val = int(mask_input)
|
||||
if not (0 <= prefix_val <= 32):
|
||||
parsed_int = int(mask_input)
|
||||
if not (0 <= parsed_int <= 32):
|
||||
raise ValueError(f"Invalid prefix string: '{mask_input}'. Must be between 0 and 32.")
|
||||
self._prefix = prefix_val
|
||||
prefix_val = parsed_int
|
||||
except ValueError:
|
||||
# Try to interpret as netmask string, e.g., "255.255.255.0"
|
||||
parsed_prefix = self._netmask_str_to_prefix(mask_input)
|
||||
if parsed_prefix is None:
|
||||
parsed_prefix_from_str = self._netmask_str_to_prefix(mask_input)
|
||||
if parsed_prefix_from_str is None:
|
||||
raise ValueError(f"Invalid netmask string format: '{mask_input}'.")
|
||||
self._prefix = parsed_prefix
|
||||
prefix_val = parsed_prefix_from_str
|
||||
else:
|
||||
raise TypeError(f"Invalid type for mask_input: {type(mask_input)}. Must be int or str.")
|
||||
|
||||
self._mask_int = self._prefix_to_mask_int(self._prefix)
|
||||
return prefix_val
|
||||
|
||||
@staticmethod
|
||||
def _is_valid_ip_octet_str(octet_str: str) -> bool:
|
||||
|
@ -90,17 +97,61 @@ class IP4Mask:
|
|||
return self._prefix == other._prefix
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def Helper(input_str):
|
||||
if re.match(r"^\s*IP4Mask\\b", input_str, re.IGNORECASE):
|
||||
return 'Máscara: IP4Mask[24], IP4Mask[255.255.255.0]. Funciones: get_prefix_int(), get_netmask_str(), hosts_count()'
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def PopupFunctionList():
|
||||
return [
|
||||
("get_prefix_int", "Obtiene prefijo CIDR (ej: 24)"),
|
||||
("get_netmask_str", "Obtiene máscara como string (ej: 255.255.255.0)"),
|
||||
("hosts_count", "Número de hosts disponibles"),
|
||||
("to_sympy", "Convierte a expresión SymPy para álgebra"),
|
||||
]
|
||||
|
||||
def hosts_count(self):
|
||||
"""Número de hosts disponibles"""
|
||||
return 2**(32 - self._prefix) - 2 if self._prefix < 31 else 0
|
||||
|
||||
def to_sympy(self):
|
||||
"""Convierte a SymPy cuando se necesite álgebra"""
|
||||
return sympy.sympify(self._prefix)
|
||||
|
||||
class Class_IP4(SympyClassBase):
|
||||
"""Clase híbrida para direcciones IPv4"""
|
||||
|
||||
def __new__(cls, *args):
|
||||
"""Crear objeto SymPy válido"""
|
||||
obj = SympyClassBase.__new__(cls)
|
||||
def __new__(cls, *args, **kwargs):
|
||||
temp_ip_str_candidate = args[0] if args else ""
|
||||
temp_ip_str = ""
|
||||
if isinstance(temp_ip_str_candidate, str):
|
||||
if '/' in temp_ip_str_candidate:
|
||||
temp_ip_str = temp_ip_str_candidate.split('/', 1)[0].strip()
|
||||
elif ' ' in temp_ip_str_candidate:
|
||||
temp_ip_str = temp_ip_str_candidate.split(' ', 1)[0].strip()
|
||||
else:
|
||||
temp_ip_str = temp_ip_str_candidate.strip()
|
||||
|
||||
if IP4Mask._is_valid_ip_string(temp_ip_str):
|
||||
ip_parts_for_new = [int(x) for x in temp_ip_str.split('.')]
|
||||
ip_int_for_new = (ip_parts_for_new[0] << 24) | \
|
||||
(ip_parts_for_new[1] << 16) | \
|
||||
(ip_parts_for_new[2] << 8) | \
|
||||
ip_parts_for_new[3]
|
||||
obj = SympyClassBase.__new__(cls, ip_int_for_new)
|
||||
else:
|
||||
raise ValueError(f"Invalid IP address format for __new__: {temp_ip_str}")
|
||||
else:
|
||||
if not args:
|
||||
raise ValueError("IP4 constructor requires arguments.")
|
||||
obj = SympyClassBase.__new__(cls, *args)
|
||||
|
||||
return obj
|
||||
|
||||
def __init__(self, *args):
|
||||
"""Inicialización de IP4"""
|
||||
self._raw_constructor_args = args # Store for __repr__
|
||||
self._raw_constructor_args = args
|
||||
|
||||
ip_str: str
|
||||
self._mask_obj: Optional[IP4Mask] = None
|
||||
|
@ -114,109 +165,93 @@ class Class_IP4(SympyClassBase):
|
|||
|
||||
if len(args) == 1:
|
||||
input_str = args[0]
|
||||
# Try "ip/prefix"
|
||||
if '/' in input_str:
|
||||
parts = input_str.split('/', 1)
|
||||
ip_str = parts[0].strip()
|
||||
if len(parts) > 1 and parts[1].strip():
|
||||
self._mask_obj = IP4Mask(parts[1].strip())
|
||||
# If no prefix after '/', it's just an IP
|
||||
# Try "ip mask_str" (space separated)
|
||||
elif ' ' in input_str:
|
||||
parts = input_str.split()
|
||||
parts = input_str.split(' ', 1)
|
||||
ip_str = parts[0].strip()
|
||||
if len(parts) > 1 and parts[1].strip():
|
||||
self._mask_obj = IP4Mask(parts[1].strip())
|
||||
# If no mask after space, it's just an IP
|
||||
else: # Just an IP string
|
||||
else:
|
||||
ip_str = input_str.strip()
|
||||
|
||||
elif len(args) == 2:
|
||||
ip_str = args[0].strip()
|
||||
mask_arg = args[1]
|
||||
|
||||
if isinstance(mask_arg, IP4Mask): # Allow passing IP4Mask instance directly
|
||||
if isinstance(mask_arg, IP4Mask):
|
||||
self._mask_obj = mask_arg
|
||||
elif isinstance(mask_arg, (str, int)): # Parser will pass str, programmatic use might pass int
|
||||
elif isinstance(mask_arg, (str, int)):
|
||||
self._mask_obj = IP4Mask(mask_arg)
|
||||
else:
|
||||
raise TypeError(f"Second argument (mask) for IP4 must be int, str, or IP4Mask instance, got {type(mask_arg)}")
|
||||
else:
|
||||
raise ValueError(f"IP4 constructor takes 1 or 2 arguments, got {len(args)}: {args}")
|
||||
|
||||
if not IP4Mask._is_valid_ip_string(ip_str): # Use IP4Mask's validator
|
||||
if not IP4Mask._is_valid_ip_string(ip_str):
|
||||
raise ValueError(f"Invalid IP address format: {ip_str}")
|
||||
|
||||
self._ip_str = ip_str
|
||||
ip_parts = [int(x) for x in ip_str.split('.')]
|
||||
self._ip_int = (ip_parts[0] << 24) | (ip_parts[1] << 16) | (ip_parts[2] << 8) | ip_parts[3]
|
||||
|
||||
# Determine the 'original_str' for SympyClassBase's _sympystr.
|
||||
# This string is what appears inside ClassName(...) in Sympy output.
|
||||
# It should reflect the arguments as they would be if typed in brackets.
|
||||
sympy_base_original_str: str
|
||||
if len(args) == 1 and isinstance(args[0], str):
|
||||
# Covers "1.1.1.1/24", "1.1.1.1 255.255.0.0", or just "1.1.1.1"
|
||||
sympy_base_original_str = args[0]
|
||||
elif len(args) == 2:
|
||||
# Reconstruct as "ip_str;mask_representation"
|
||||
mask_arg_for_repr = args[1]
|
||||
if isinstance(mask_arg_for_repr, IP4Mask): # Should not happen from parser
|
||||
if isinstance(mask_arg_for_repr, IP4Mask):
|
||||
mask_repr_str = str(mask_arg_for_repr.get_prefix_int())
|
||||
elif isinstance(mask_arg_for_repr, int):
|
||||
mask_repr_str = str(mask_arg_for_repr)
|
||||
else: # string
|
||||
mask_repr_str = str(mask_arg_for_repr) # e.g., "24" or "255.255.255.0"
|
||||
else:
|
||||
mask_repr_str = str(mask_arg_for_repr)
|
||||
sympy_base_original_str = f"{args[0]};{mask_repr_str}"
|
||||
else: # Only ip_str was derived, no mask (or error caught earlier)
|
||||
else:
|
||||
sympy_base_original_str = self._ip_str
|
||||
|
||||
super().__init__(self._ip_int, sympy_base_original_str)
|
||||
|
||||
def __repr__(self):
|
||||
# This should be a valid Python expression to recreate the object.
|
||||
arg_reprs = [repr(arg) for arg in self._raw_constructor_args]
|
||||
return f"{self.__class__.__name__}({', '.join(arg_reprs)})"
|
||||
|
||||
def __str__(self):
|
||||
"""Representación string para display"""
|
||||
if self._mask_obj:
|
||||
return f"{self._ip_str}/{self._mask_obj.get_prefix_int()}"
|
||||
return self._ip_str
|
||||
|
||||
def _sympystr(self, printer):
|
||||
"""Representación SymPy string"""
|
||||
return str(self)
|
||||
|
||||
@staticmethod
|
||||
def Helper(input_str):
|
||||
"""Ayuda contextual para IP4"""
|
||||
if re.match(r"^\s*IP4\b", input_str, re.IGNORECASE):
|
||||
return ('Ej: IP4[192.168.1.1/24], IP4[10.0.0.1;8], IP4[172.16.0.5;255.255.0.0]\n'
|
||||
'Funciones: NetworkAddress(), BroadcastAddress(), Nodes(), get_netmask_str(), get_prefix_length()')
|
||||
if re.match(r"^\s*IP4\\b", input_str, re.IGNORECASE):
|
||||
return ('Ej: IP4[192.168.1.1/24], IP4[10.0.0.1;8], IP4[172.16.0.5;255.255.0.0]\\n'
|
||||
'Funciones: NetworkAddress(), BroadcastAddress(), Nodes(), get_netmask_str(), get_prefix_length(), mask()')
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def PopupFunctionList():
|
||||
"""Lista de métodos sugeridos para autocompletado de IP4"""
|
||||
return [
|
||||
("NetworkAddress", "Obtiene la dirección de red"),
|
||||
("BroadcastAddress", "Obtiene la dirección de broadcast"),
|
||||
("Nodes", "Cantidad de nodos usables en la subred"),
|
||||
("NetworkAddress", "Dirección de red"),
|
||||
("BroadcastAddress", "Dirección de broadcast"),
|
||||
("Nodes", "Hosts disponibles"),
|
||||
("mask", "Objeto máscara con sus métodos"),
|
||||
("get_netmask_str", "Obtiene la máscara de red (ej: 255.255.255.0)"),
|
||||
("get_prefix_length", "Obtiene la longitud del prefijo CIDR (ej: 24)"),
|
||||
]
|
||||
|
||||
def get_netmask_str(self) -> Optional[str]:
|
||||
"""Returns the netmask as a string (e.g., "255.255.255.0") if a mask is defined."""
|
||||
return self._mask_obj.get_mask_str() if self._mask_obj else None
|
||||
|
||||
def get_prefix_length(self) -> Optional[int]:
|
||||
"""Returns the prefix length (e.g., 24) if a mask is defined."""
|
||||
return self._mask_obj.get_prefix_int() if self._mask_obj else None
|
||||
|
||||
def NetworkAddress(self):
|
||||
"""Obtiene la dirección de red"""
|
||||
prefix = self.get_prefix_length()
|
||||
if prefix is None:
|
||||
raise ValueError("No prefix/mask defined for NetworkAddress calculation.")
|
||||
|
@ -231,10 +266,9 @@ class Class_IP4(SympyClassBase):
|
|||
network_int & 0xFF
|
||||
]
|
||||
network_str = '.'.join(str(x) for x in parts)
|
||||
return Class_IP4(network_str, prefix) # Return new IP4 object for the network
|
||||
return Class_IP4(network_str, prefix)
|
||||
|
||||
def BroadcastAddress(self):
|
||||
"""Obtiene la dirección de broadcast"""
|
||||
prefix = self.get_prefix_length()
|
||||
if prefix is None:
|
||||
raise ValueError("No prefix/mask defined for BroadcastAddress calculation.")
|
||||
|
@ -249,14 +283,19 @@ class Class_IP4(SympyClassBase):
|
|||
broadcast_int & 0xFF
|
||||
]
|
||||
broadcast_str = '.'.join(str(x) for x in parts)
|
||||
return Class_IP4(broadcast_str, prefix) # Return new IP4 object for broadcast
|
||||
return Class_IP4(broadcast_str, prefix)
|
||||
|
||||
def Nodes(self):
|
||||
"""Obtiene el número de nodos disponibles"""
|
||||
prefix = self.get_prefix_length()
|
||||
if prefix is None:
|
||||
raise ValueError("No prefix/mask defined for Nodes calculation.")
|
||||
|
||||
if prefix >= 31: # For /31 and /32, typically 0 usable host addresses in standard subnetting
|
||||
if prefix >= 31:
|
||||
return 0
|
||||
return (2 ** (32 - prefix)) - 2
|
||||
return (2 ** (32 - prefix)) - 2
|
||||
|
||||
def mask(self) -> Optional[IP4Mask]:
|
||||
"""Retorna objeto máscara para autocompletado"""
|
||||
if not self._mask_obj:
|
||||
raise ValueError("No mask defined for this IP4 object.")
|
||||
return self._mask_obj
|
|
@ -300,13 +300,11 @@ class HybridCalculatorApp:
|
|||
current_line_num = int(line_num_str)
|
||||
char_idx_after_dot = int(char_num_str)
|
||||
|
||||
if char_idx_after_dot == 0: # Should not happen if a dot was typed
|
||||
if char_idx_after_dot == 0:
|
||||
print("DEBUG: Autocomplete: Cursor at beginning of line after dot. No action.")
|
||||
return
|
||||
|
||||
# Índice del punto en la línea actual (0-based)
|
||||
dot_char_index_in_line = char_idx_after_dot - 1
|
||||
# Texto en la línea actual HASTA el punto (sin incluirlo)
|
||||
text_on_line_up_to_dot = self.input_text.get(f"{current_line_num}.0", f"{current_line_num}.{dot_char_index_in_line}")
|
||||
|
||||
stripped_text_before_dot = text_on_line_up_to_dot.strip()
|
||||
|
@ -315,23 +313,45 @@ class HybridCalculatorApp:
|
|||
if not stripped_text_before_dot:
|
||||
print("DEBUG: Dot on empty line or after spaces. Offering global suggestions.")
|
||||
suggestions = []
|
||||
custom_types_suggestions = [
|
||||
("Hex", "Tipo Hexadecimal. Ej: Hex[FF]"),
|
||||
("Bin", "Tipo Binario. Ej: Bin[1010]"),
|
||||
("Dec", "Tipo Decimal. Ej: Dec[42]"),
|
||||
("IP4", "Tipo Dirección IPv4. Ej: IP4[1.2.3.4/24]"),
|
||||
("Chr", "Tipo Carácter. Ej: Chr[A]"),
|
||||
]
|
||||
suggestions.extend(custom_types_suggestions)
|
||||
|
||||
# MODIFIED: Get suggestions from HybridEvaluationEngine's base_context
|
||||
if hasattr(self.engine, 'base_context') and isinstance(self.engine.base_context, dict):
|
||||
for name, class_or_func in self.engine.base_context.items():
|
||||
# Solo queremos clases (tipos) y funciones para el autocompletado global principal.
|
||||
# Evitamos alias en minúscula si la versión capitalizada ya está (heurística simple).
|
||||
if name[0].isupper(): # Prioritize capitalized names for classes/main functions
|
||||
hint = f"Tipo o función: {name}"
|
||||
if hasattr(class_or_func, '__doc__') and class_or_func.__doc__:
|
||||
first_line_doc = class_or_func.__doc__.strip().split('\n')[0]
|
||||
hint = f"{name} - {first_line_doc}"
|
||||
elif hasattr(class_or_func, 'Helper'): # Usar Helper si está disponible
|
||||
# Para obtener un hint del Helper, necesitamos llamarlo.
|
||||
# Algunas clases Helper esperan el nombre de la clase.
|
||||
try:
|
||||
helper_text = class_or_func.Helper(name) # Pasar el nombre de la clase
|
||||
if helper_text:
|
||||
hint = helper_text.split('\n')[0] # Primera línea del helper
|
||||
except Exception as e_helper:
|
||||
print(f"DEBUG: Error calling Helper for {name}: {e_helper}")
|
||||
pass # Mantener el hint genérico
|
||||
suggestions.append((name, hint))
|
||||
|
||||
# Añadir funciones de SympyHelper (si no están ya en base_context de forma similar)
|
||||
# Considerar si SympyHelper.PopupFunctionList() devuelve cosas ya cubiertas.
|
||||
try:
|
||||
sympy_functions = SympyHelper.PopupFunctionList()
|
||||
if sympy_functions:
|
||||
suggestions.extend(sympy_functions)
|
||||
# Evitar duplicados si los nombres ya están de base_context
|
||||
current_suggestion_names = {s[0] for s in suggestions}
|
||||
for fname, fhint in sympy_functions:
|
||||
if fname not in current_suggestion_names:
|
||||
suggestions.append((fname, fhint))
|
||||
except Exception as e:
|
||||
print(f"DEBUG: Error calling SympyHelper.PopupFunctionList() for global: {e}")
|
||||
|
||||
if suggestions:
|
||||
# Ordenar alfabéticamente para consistencia
|
||||
suggestions.sort(key=lambda x: x[0])
|
||||
self._show_autocomplete_popup(suggestions, is_global_popup=True)
|
||||
return
|
||||
|
||||
|
|
|
@ -11,11 +11,11 @@ from contextlib import contextmanager
|
|||
from tl_bracket_parser import BracketParser
|
||||
from tl_popup import PlotResult
|
||||
from sympy_Base import SympyClassBase
|
||||
from ip4_type import Class_IP4 as Class_IP4
|
||||
from hex_type import Class_Hex as Class_Hex
|
||||
from bin_type import Class_Bin as Class_Bin
|
||||
from dec_type import Class_Dec as Class_Dec
|
||||
from chr_type import Class_Chr as Class_Chr
|
||||
from ip4_type import Class_IP4, IP4Mask
|
||||
from hex_type import Class_Hex
|
||||
from bin_type import Class_Bin
|
||||
from dec_type import Class_Dec
|
||||
from chr_type import Class_Chr
|
||||
|
||||
|
||||
class HybridEvaluationEngine:
|
||||
|
@ -90,12 +90,14 @@ class HybridEvaluationEngine:
|
|||
'Dec': Class_Dec,
|
||||
'IP4': Class_IP4,
|
||||
'Chr': Class_Chr,
|
||||
'IP4Mask': IP4Mask,
|
||||
# Alias en minúsculas
|
||||
'hex': Class_Hex,
|
||||
'bin': Class_Bin,
|
||||
'dec': Class_Dec,
|
||||
'ip4': Class_IP4,
|
||||
'chr': Class_Chr,
|
||||
'ip4mask': IP4Mask,
|
||||
}
|
||||
|
||||
# Funciones de utilidad
|
||||
|
|
|
@ -5,24 +5,31 @@ import sympy
|
|||
from sympy import Basic, Symbol, sympify
|
||||
from typing import Any, Optional, Dict
|
||||
import re
|
||||
from class_base import ClassBase
|
||||
|
||||
|
||||
class SympyClassBase(Basic):
|
||||
"""
|
||||
Clase base híbrida que combina SymPy Basic con funcionalidad de calculadora
|
||||
Todas las clases especializadas deben heredar de esta
|
||||
"""
|
||||
class SympyClassBase(ClassBase, sympy.Basic):
|
||||
"""Para clases que necesitan álgebra completa"""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""Crear objeto SymPy válido"""
|
||||
obj = Basic.__new__(cls)
|
||||
# La subclase (ej. Class_IP4) es responsable de pasar los argumentos correctos
|
||||
# que sympy.Basic.__new__ espera.
|
||||
obj = sympy.Basic.__new__(cls, *args, **kwargs)
|
||||
return obj
|
||||
|
||||
def __init__(self, value, original_str=""):
|
||||
"""Inicialización de funcionalidad especializada"""
|
||||
self._value = value
|
||||
self._original_str = original_str
|
||||
self._init_specialized()
|
||||
ClassBase.__init__(self, value, original_str)
|
||||
# La inicialización de sympy.Basic se maneja principalmente a través de __new__.
|
||||
# Atributos adicionales de sympy como self.args son establecidos por sympy.Basic
|
||||
# basado en los argumentos pasados a __new__.
|
||||
|
||||
def _sympystr(self, printer):
|
||||
# Las subclases deben implementar esto para una representación SymPy adecuada.
|
||||
# Por defecto, usa el __str__ de ClassBase, que es str(self.value).
|
||||
# Si self.value es un objeto Sympy, str(self.value) ya dará una buena representación.
|
||||
# Si self.value no es un objeto Sympy pero se desea una forma SymPy específica,
|
||||
# esto debería ser sobreescrito.
|
||||
return str(self.value)
|
||||
|
||||
def _init_specialized(self):
|
||||
"""Override en subclases para inicialización especializada"""
|
||||
|
@ -49,10 +56,6 @@ class SympyClassBase(Basic):
|
|||
"""Función constructora para SymPy"""
|
||||
return self.__class__
|
||||
|
||||
def _sympystr(self, printer):
|
||||
"""Representación SymPy string"""
|
||||
return f"{self.__class__.__name__}({self._original_str})"
|
||||
|
||||
def _latex(self, printer):
|
||||
"""Representación LaTeX"""
|
||||
return self._sympystr(printer)
|
||||
|
|
|
@ -10,7 +10,7 @@ class BracketParser:
|
|||
"""Parser que convierte sintaxis con corchetes y detecta ecuaciones contextualmente"""
|
||||
|
||||
# Clases que soportan sintaxis con corchetes
|
||||
BRACKET_CLASSES = {'IP4', 'Hex', 'Bin', 'Date', 'Dec', 'Chr'}
|
||||
BRACKET_CLASSES = {'IP4', 'Hex', 'Bin', 'Date', 'Dec', 'Chr', 'IP4Mask'}
|
||||
|
||||
# Operadores de comparación que pueden formar ecuaciones
|
||||
EQUATION_OPERATORS = {'==', '!=', '<', '<=', '>', '>=', '='}
|
||||
|
|
Loading…
Reference in New Issue