Tracebacks in Jupyter notebooks¶
Andreas Freise, 16/04/2020
The following demonstrates how Finesse handles parse errors. When run from IPython or Jupyter the full traceback is suppressed and only the parser error itself is shown. When run from Python it always returns the full traceback.
You can print the latest full traceback with finesse.tb().
If you want to always see the full traceback, for example, during debugging, you can set this with finesse.show_tracebacks()
We use a very simple example model for the demonstration:
from finesse.env import is_interactive
print(is_interactive())
True
import finesse
code = """
l laser P=1
pd tmp laser.p1.o
"""
kat = finesse.Model()
kat.parse(code)
A syntax error in the katscript gives a parser error:
code = """
l1 laser P=1
pd tmp laser.p1.o
"""
kat = finesse.Model()
kat.parse(code)
KatSyntaxError: (use finesse.tb() to see the full traceback)
line 2: unknown element 'l1'. Did you mean 'l'?
1:
-->2: l1 laser P=1
^^
3: pd tmp laser.p1.o
We can print the full traceback:
finesse.tb(colors=False)
---------------------------------------------------------------------------
KatSyntaxError Traceback (most recent call last)
Cell In[3], line 7
1 code = """
2 l1 laser P=1
3 pd tmp laser.p1.o
4 """
6 kat = finesse.Model()
----> 7 kat.parse(code)
File /usr/local/lib/python3.13/site-packages/finesse/model.py:83, in locked_when_built.<locals>.wrapper(self, *args, **kwargs)
79 if self.is_built:
80 raise Exception(
81 f"Model has been built for a simulation, cannot use {func} here"
82 )
---> 83 return func(self, *args, **kwargs)
File /usr/local/lib/python3.13/site-packages/finesse/model.py:2264, in Model.parse(self, text, spec)
2245 """Parses kat script and adds the resulting objects to the model.
2246
2247 Parameters
(...)
2260 parse_legacy_file : Parse Finesse 2 kat script file.
2261 """
2262 from .script import parse
-> 2264 parse(text, model=self, spec=spec)
File /usr/local/lib/python3.13/site-packages/finesse/script/__init__.py:44, in parse(text, model, spec)
41 from .compiler import KatCompiler
43 compiler = KatCompiler(spec=spec)
---> 44 return compiler.compile(text, model=model)
File /usr/local/lib/python3.13/site-packages/finesse/script/compiler.py:166, in KatCompiler.compile(self, string, **kwargs)
148 def compile(self, string, **kwargs):
149 """Compile the contents of `string`.
150
151 Parameters
(...)
164 The model compiled from reading `string`.
165 """
--> 166 return self.compile_file(StringIO(string), **kwargs)
File /usr/local/lib/python3.13/site-packages/finesse/script/compiler.py:215, in KatCompiler.compile_file(self, fobj, model, resolve, build)
212 self._reraise_parser_error_in_spec_context(e)
214 # Build the parse graph.
--> 215 self._fill(script, ROOT_NODE_NAME)
217 # At this stage there shouldn't be any dependencies between branches.
218 assert self.graph.is_tree()
File /usr/local/lib/python3.13/site-packages/finesse/script/compiler.py:274, in KatCompiler._fill(self, value, path, **attributes)
272 for order, argument in enumerate(value.arguments):
273 argument_path = self.graph.item_node_name(order, path)
--> 274 self._fill(argument, argument_path)
275 self.graph.add_edge(
276 argument_path, path, type=KatEdgeType.ARGUMENT, order=order
277 )
279 return attributes
File /usr/local/lib/python3.13/site-packages/finesse/script/compiler.py:266, in KatCompiler._fill(self, value, path, **attributes)
264 def _fill(self, value, path, **attributes):
265 attributes = merge_attributes(
--> 266 attributes, self._item_node_attributes(value, path)
267 )
268 self.graph.add_node(path, **attributes)
270 if hasattr(value, "arguments"):
271 # Assemble arguments.
File /usr/local/lib/python3.13/functools.py:985, in singledispatchmethod.__get__.<locals>._method(*args, **kwargs)
982 if not args:
983 raise TypeError(f'{funcname} requires at least '
984 '1 positional argument')
--> 985 return dispatch(args[0].__class__).__get__(obj, cls)(*args, **kwargs)
File /usr/local/lib/python3.13/site-packages/finesse/script/compiler.py:341, in KatCompiler._(self, element, path)
337 else:
338 msg = _get_unknown_token_message(
339 "element", directive_token.raw_value, self.spec.elements.keys()
340 )
--> 341 raise KatSyntaxError(
342 msg,
343 self.script,
344 directive_token,
345 )
346 return {
347 "token": element.directive,
348 "name_token": element.name,
349 "type": KatNodeType.ELEMENT,
350 "extra_tokens": element.extra,
351 }
KatSyntaxError: (use finesse.tb() to see the full traceback)
line 2: unknown element 'l1'. Did you mean 'l'?
1:
-->2: l1 laser P=1
^^
3: pd tmp laser.p1.o
To switch tracebacks on globally:
finesse.show_tracebacks(True)
False
code = """
l1 laser P=1
pd tmp laser.p1.o
"""
kat = finesse.Model()
kat.parse(code)
---------------------------------------------------------------------------
KatSyntaxError Traceback (most recent call last)
Cell In[6], line 7
1 code = """
2 l1 laser P=1
3 pd tmp laser.p1.o
4 """
6 kat = finesse.Model()
----> 7 kat.parse(code)
File /usr/local/lib/python3.13/site-packages/finesse/model.py:83, in locked_when_built.<locals>.wrapper(self, *args, **kwargs)
79 if self.is_built:
80 raise Exception(
81 f"Model has been built for a simulation, cannot use {func} here"
82 )
---> 83 return func(self, *args, **kwargs)
File /usr/local/lib/python3.13/site-packages/finesse/model.py:2264, in Model.parse(self, text, spec)
2245 """Parses kat script and adds the resulting objects to the model.
2246
2247 Parameters
(...)
2260 parse_legacy_file : Parse Finesse 2 kat script file.
2261 """
2262 from .script import parse
-> 2264 parse(text, model=self, spec=spec)
File /usr/local/lib/python3.13/site-packages/finesse/script/__init__.py:44, in parse(text, model, spec)
41 from .compiler import KatCompiler
43 compiler = KatCompiler(spec=spec)
---> 44 return compiler.compile(text, model=model)
File /usr/local/lib/python3.13/site-packages/finesse/script/compiler.py:166, in KatCompiler.compile(self, string, **kwargs)
148 def compile(self, string, **kwargs):
149 """Compile the contents of `string`.
150
151 Parameters
(...)
164 The model compiled from reading `string`.
165 """
--> 166 return self.compile_file(StringIO(string), **kwargs)
File /usr/local/lib/python3.13/site-packages/finesse/script/compiler.py:215, in KatCompiler.compile_file(self, fobj, model, resolve, build)
212 self._reraise_parser_error_in_spec_context(e)
214 # Build the parse graph.
--> 215 self._fill(script, ROOT_NODE_NAME)
217 # At this stage there shouldn't be any dependencies between branches.
218 assert self.graph.is_tree()
File /usr/local/lib/python3.13/site-packages/finesse/script/compiler.py:274, in KatCompiler._fill(self, value, path, **attributes)
272 for order, argument in enumerate(value.arguments):
273 argument_path = self.graph.item_node_name(order, path)
--> 274 self._fill(argument, argument_path)
275 self.graph.add_edge(
276 argument_path, path, type=KatEdgeType.ARGUMENT, order=order
277 )
279 return attributes
File /usr/local/lib/python3.13/site-packages/finesse/script/compiler.py:266, in KatCompiler._fill(self, value, path, **attributes)
264 def _fill(self, value, path, **attributes):
265 attributes = merge_attributes(
--> 266 attributes, self._item_node_attributes(value, path)
267 )
268 self.graph.add_node(path, **attributes)
270 if hasattr(value, "arguments"):
271 # Assemble arguments.
File /usr/local/lib/python3.13/functools.py:985, in singledispatchmethod.__get__.<locals>._method(*args, **kwargs)
982 if not args:
983 raise TypeError(f'{funcname} requires at least '
984 '1 positional argument')
--> 985 return dispatch(args[0].__class__).__get__(obj, cls)(*args, **kwargs)
File /usr/local/lib/python3.13/site-packages/finesse/script/compiler.py:341, in KatCompiler._(self, element, path)
337 else:
338 msg = _get_unknown_token_message(
339 "element", directive_token.raw_value, self.spec.elements.keys()
340 )
--> 341 raise KatSyntaxError(
342 msg,
343 self.script,
344 directive_token,
345 )
346 return {
347 "token": element.directive,
348 "name_token": element.name,
349 "type": KatNodeType.ELEMENT,
350 "extra_tokens": element.extra,
351 }
KatSyntaxError:
line 2: unknown element 'l1'. Did you mean 'l'?
1:
-->2: l1 laser P=1
^^
3: pd tmp laser.p1.o
finesse.show_tracebacks() can also switch tracebacks off again:
finesse.show_tracebacks(False)
True