@@ -58,15 +58,16 @@ def log_embedded_error(self, message: str):
5858 """Log an error message in the embedded logbook."""
5959 self .textEdit_2 .append (f"<span style='color: red;'>{ message } </span>" )
6060 self .textEdit_2 .verticalScrollBar ().setValue (self .textEdit_2 .verticalScrollBar ().maximum ())
61-
61+ logger .error (message )
62+
6263 def log_embedded (self , message : str ):
6364 """Log a message in the embedded logbook."""
6465 self .textEdit_2 .append (f"<span style='color: black;'>{ message } </span>" )
6566 self .textEdit_2 .verticalScrollBar ().setValue (self .textEdit_2 .verticalScrollBar ().maximum ())
6667
6768 def getConstraintText (self , fit_params : str ) -> str :
6869 """Get the default text for the constraints editor"""
69-
70+
7071 self .constraintText = (
7172 "# Write libraries to be imported here.\n "
7273 "from numpy import inf\n "
@@ -160,7 +161,7 @@ def as_ast(text: str):
160161 last_lines = all_lines [- 1 :]
161162 traceback_to_show = '\n ' .join (last_lines )
162163 logger .error (traceback_to_show )
163- self .log_embedded_error (f"Error parsing constraints text: { e } " )
164+ self .log_embedded_error (f"{ e } " )
164165 return None
165166
166167 def expand_center_of_mass_pars (constraint : ast .Assign ) -> list [ast .Assign ]:
@@ -222,9 +223,15 @@ def parse_ast(tree: ast.AST):
222223 imports .append (node )
223224
224225 case ast .Assign ():
226+ if len (node .targets ) != 1 or isinstance (node .targets [0 ], ast .Tuple ) or isinstance (node .value , ast .Tuple ):
227+ self .log_embedded_error (f"Tuple assignment is not supported (line { node .lineno } )." )
228+ raise ValueError (f"Tuple assignment is not supported (line { node .lineno } )." )
229+
225230 if node .targets [0 ].id == 'parameters' :
226231 params = node
227- elif node .targets [0 ].id .startswith ('dCOM' ) or node .targets [0 ].id .startswith ('COM' ):
232+ continue
233+
234+ if node .targets [0 ].id .startswith ('dCOM' ) or node .targets [0 ].id .startswith ('COM' ):
228235 constraints .append (expand_center_of_mass_pars (node ))
229236 else :
230237 constraints .append (node )
@@ -233,65 +240,65 @@ def parse_ast(tree: ast.AST):
233240 def extract_symbols (constraints : list [ast .AST ]) -> tuple [list [str ], list [str ]]:
234241 """Extract all symbols used in the constraints."""
235242 lhs , rhs = set (), set ()
243+ lineno = {}
236244 for node in constraints :
237245 # left-hand side of assignment
238246 for target in node .targets :
239247 match target :
240248 case ast .Name ():
241249 lhs .add (target .id )
250+ lineno [target .id ] = target .lineno
242251 case ast .Tuple ():
243252 for elt in target .elts :
244253 if isinstance (elt , ast .Name ):
245254 lhs .add (elt .id )
255+ lineno [elt .id ] = elt .lineno
246256
247257 # right-hand side of assignment
248258 for value in ast .walk (node .value ):
249259 match value :
250260 case ast .Name ():
251261 rhs .add (value .id )
262+ lineno [value .id ] = value .lineno
252263 case ast .Tuple :
253264 for elt in value .elts :
254265 if isinstance (elt , ast .Name ):
255266 rhs .add (elt .id )
267+ lineno [elt .id ] = elt .lineno
256268
257- return lhs , rhs
269+ return lhs , rhs , lineno
258270
259271 def validate_params (params : ast .AST ):
260272 if params is None :
261- logger .error ("No parameters found in constraints text." )
262273 self .log_embedded_error ("No parameters found in constraints text." )
263274 raise ValueError ("No parameters found in constraints text." )
264275
265- def validate_symbols (lhs : list [str ], rhs : list [str ], fitPars : list [str ]):
276+ def validate_symbols (lhs : list [str ], rhs : list [str ], symbol_linenos : dict [ str , int ], fitPars : list [str ]):
266277 """Check if all symbols in lhs and rhs are valid parameters."""
267278 # lhs is not allowed to contain fit parameters
268279 for symbol in lhs :
269280 if symbol in fitPars or symbol [1 :] in fitPars :
270- logger .error (f"Symbol '{ symbol } ' is a fit parameter and cannot be assigned to." )
271- self .log_embedded_error (f"Symbol '{ symbol } ' is a fit parameter and cannot be assigned to." )
272- raise ValueError (f"Symbol '{ symbol } ' is a fit parameter and cannot be assigned to." )
281+ self .log_embedded_error (f"Symbol '{ symbol } ' is a fit parameter and cannot be assigned to (line { symbol_linenos [symbol ]} )." )
282+ raise ValueError (f"Symbol '{ symbol } ' is a fit parameter and cannot be assigned to (line { symbol_linenos [symbol ]} )." )
273283
274284 for symbol in rhs :
275285 is_fit_par = symbol in fitPars or symbol [1 :] in fitPars
276286 is_defined = symbol in lhs
277287 if not is_fit_par and not is_defined :
278- logger .error (f"Symbol '{ symbol } ' is undefined." )
279- self .log_embedded_error (f"Symbol '{ symbol } ' is undefined." )
280- raise ValueError (f"Symbol '{ symbol } ' is undefined." )
288+ self .log_embedded_error (f"Symbol '{ symbol } ' is undefined (line { symbol_linenos [symbol ]} )." )
289+ raise ValueError (f"Symbol '{ symbol } ' is undefined (line { symbol_linenos [symbol ]} )." )
281290
282291 def validate_imports (imports : list [ast .ImportFrom | ast .Import ]):
283292 """Check if all imports are valid."""
284293 for imp in imports :
285294 if isinstance (imp , ast .ImportFrom ):
286295 if not importlib .util .find_spec (imp .module ):
287- logger .error (f"Module '{ imp .module } ' not found." )
288- self .log_embedded_error (f"Module '{ imp .module } ' not found." )
296+ self .log_embedded_error (f"Module '{ imp .module } ' not found (line { imp .lineno } )." )
289297 raise ModuleNotFoundError (f"No module named { imp .module } " )
290298 elif isinstance (imp , ast .Import ):
291299 for name in imp .names :
292300 if not importlib .util .find_spec (name .name ):
293- logger .error (f"Module '{ name .name } ' not found." )
294- self .log_embedded_error (f"Module '{ name .name } ' not found." )
301+ self .log_embedded_error (f"Module '{ name .name } ' not found (line { imp .lineno } )." )
295302 raise ModuleNotFoundError (f"No module named { name .name } " )
296303
297304 def mark_named_parameters (checkedPars : list [list [bool ]], modelPars : list [str ], symbols : set [str ]):
@@ -310,9 +317,9 @@ def in_symbols(par: str):
310317
311318 tree = as_ast (text )
312319 params , imports , constraints = parse_ast (tree )
313- lhs , rhs = extract_symbols (constraints )
320+ lhs , rhs , symbol_linenos = extract_symbols (constraints )
314321 validate_params (params )
315- validate_symbols (lhs , rhs , fitPar )
322+ validate_symbols (lhs , rhs , symbol_linenos , fitPar )
316323 validate_imports (imports )
317324
318325 params = ast .unparse (params )
0 commit comments