@@ -92,12 +92,19 @@ def _default_functions(self):
9292 env [sf_name ] = sf
9393 return env
9494
95+ def _check_for_cycles (self ):
96+ try :
97+ self ._topological_sort ()
98+ except ValueError as e :
99+ raise ValueError ("Cycle detected in alias dependencies" ) from e
100+
95101 def add_alias (self , name , expression , dtype = None , is_constant = False ):
96102 self .aliases [name ] = expression
97103 if dtype is not None :
98104 self .alias_dtypes [name ] = dtype
99105 if is_constant :
100106 self .constant_aliases .add (name )
107+ self ._check_for_cycles ()
101108
102109 def _eval_in_namespace (self , expr ):
103110 local_env = {col : self .df [col ] for col in self .df .columns }
@@ -188,17 +195,14 @@ def materialize_alias(self, name, cleanTemporary=False, dtype=None):
188195 print (f"[materialize_alias] Warning: alias '{ name } ' not found." )
189196 return
190197 expr = self .aliases [name ]
191- try :
192- result = self ._eval_in_namespace (expr )
193- result_dtype = dtype or self .alias_dtypes .get (name )
194- if result_dtype is not None :
195- try :
196- result = result .astype (result_dtype )
197- except AttributeError :
198- result = result_dtype (result )
199- self .df [name ] = result
200- except Exception as e :
201- print (f"Failed to materialize { name } : { e } " )
198+ result = self ._eval_in_namespace (expr )
199+ result_dtype = dtype or self .alias_dtypes .get (name )
200+ if result_dtype is not None :
201+ try :
202+ result = result .astype (result_dtype )
203+ except AttributeError :
204+ result = result_dtype (result )
205+ self .df [name ] = result
202206
203207 def materialize_aliases (self , targets , cleanTemporary = True , verbose = False ):
204208 import networkx as nx
0 commit comments