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.12/site-packages/finesse/model.py:79, in locked_when_built.<locals>.wrapper(self, *args, **kwargs)
     75 if self.is_built:
     76     raise Exception(
     77         f"Model has been built for a simulation, cannot use {func} here"
     78     )
---> 79 return func(self, *args, **kwargs)

File /usr/local/lib/python3.12/site-packages/finesse/model.py:2236, in Model.parse(self, text, spec)
   2217 """Parses kat script and adds the resulting objects to the model.
   2218 
   2219 Parameters
   (...)
   2232 parse_legacy_file : Parse Finesse 2 kat script file.
   2233 """
   2234 from .script import parse
-> 2236 parse(text, model=self, spec=spec)

File /usr/local/lib/python3.12/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.12/site-packages/finesse/script/compiler.py:165, in KatCompiler.compile(self, string, **kwargs)
    147 def compile(self, string, **kwargs):
    148     """Compile the contents of `string`.
    149 
    150     Parameters
   (...)
    163         The model compiled from reading `string`.
    164     """
--> 165     return self.compile_file(StringIO(string), **kwargs)

File /usr/local/lib/python3.12/site-packages/finesse/script/compiler.py:214, in KatCompiler.compile_file(self, fobj, model, resolve, build)
    211     self._reraise_parser_error_in_spec_context(e)
    213 # Build the parse graph.
--> 214 self._fill(script, ROOT_NODE_NAME)
    216 # At this stage there shouldn't be any dependencies between branches.
    217 assert self.graph.is_tree()

File /usr/local/lib/python3.12/site-packages/finesse/script/compiler.py:273, in KatCompiler._fill(self, value, path, **attributes)
    271     for order, argument in enumerate(value.arguments):
    272         argument_path = self.graph.item_node_name(order, path)
--> 273         self._fill(argument, argument_path)
    274         self.graph.add_edge(
    275             argument_path, path, type=KatEdgeType.ARGUMENT, order=order
    276         )
    278 return attributes

File /usr/local/lib/python3.12/site-packages/finesse/script/compiler.py:265, in KatCompiler._fill(self, value, path, **attributes)
    263 def _fill(self, value, path, **attributes):
    264     attributes = merge_attributes(
--> 265         attributes, self._item_node_attributes(value, path)
    266     )
    267     self.graph.add_node(path, **attributes)
    269     if hasattr(value, "arguments"):
    270         # Assemble arguments.

File /usr/local/lib/python3.12/functools.py:946, in singledispatchmethod.__get__.<locals>._method(*args, **kwargs)
    944 def _method(*args, **kwargs):
    945     method = self.dispatcher.dispatch(args[0].__class__)
--> 946     return method.__get__(obj, cls)(*args, **kwargs)

File /usr/local/lib/python3.12/site-packages/finesse/script/compiler.py:340, in KatCompiler._(self, element, path)
    336     else:
    337         msg = _get_unknown_token_message(
    338             "element", directive_token.raw_value, self.spec.elements.keys()
    339         )
--> 340         raise KatSyntaxError(
    341             msg,
    342             self.script,
    343             directive_token,
    344         )
    345 return {
    346     "token": element.directive,
    347     "name_token": element.name,
    348     "type": KatNodeType.ELEMENT,
    349     "extra_tokens": element.extra,
    350 }

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.12/site-packages/finesse/model.py:79, in locked_when_built.<locals>.wrapper(self, *args, **kwargs)
     75 if self.is_built:
     76     raise Exception(
     77         f"Model has been built for a simulation, cannot use {func} here"
     78     )
---> 79 return func(self, *args, **kwargs)

File /usr/local/lib/python3.12/site-packages/finesse/model.py:2236, in Model.parse(self, text, spec)
   2217 """Parses kat script and adds the resulting objects to the model.
   2218 
   2219 Parameters
   (...)
   2232 parse_legacy_file : Parse Finesse 2 kat script file.
   2233 """
   2234 from .script import parse
-> 2236 parse(text, model=self, spec=spec)

File /usr/local/lib/python3.12/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.12/site-packages/finesse/script/compiler.py:165, in KatCompiler.compile(self, string, **kwargs)
    147 def compile(self, string, **kwargs):
    148     """Compile the contents of `string`.
    149 
    150     Parameters
   (...)
    163         The model compiled from reading `string`.
    164     """
--> 165     return self.compile_file(StringIO(string), **kwargs)

File /usr/local/lib/python3.12/site-packages/finesse/script/compiler.py:214, in KatCompiler.compile_file(self, fobj, model, resolve, build)
    211     self._reraise_parser_error_in_spec_context(e)
    213 # Build the parse graph.
--> 214 self._fill(script, ROOT_NODE_NAME)
    216 # At this stage there shouldn't be any dependencies between branches.
    217 assert self.graph.is_tree()

File /usr/local/lib/python3.12/site-packages/finesse/script/compiler.py:273, in KatCompiler._fill(self, value, path, **attributes)
    271     for order, argument in enumerate(value.arguments):
    272         argument_path = self.graph.item_node_name(order, path)
--> 273         self._fill(argument, argument_path)
    274         self.graph.add_edge(
    275             argument_path, path, type=KatEdgeType.ARGUMENT, order=order
    276         )
    278 return attributes

File /usr/local/lib/python3.12/site-packages/finesse/script/compiler.py:265, in KatCompiler._fill(self, value, path, **attributes)
    263 def _fill(self, value, path, **attributes):
    264     attributes = merge_attributes(
--> 265         attributes, self._item_node_attributes(value, path)
    266     )
    267     self.graph.add_node(path, **attributes)
    269     if hasattr(value, "arguments"):
    270         # Assemble arguments.

File /usr/local/lib/python3.12/functools.py:946, in singledispatchmethod.__get__.<locals>._method(*args, **kwargs)
    944 def _method(*args, **kwargs):
    945     method = self.dispatcher.dispatch(args[0].__class__)
--> 946     return method.__get__(obj, cls)(*args, **kwargs)

File /usr/local/lib/python3.12/site-packages/finesse/script/compiler.py:340, in KatCompiler._(self, element, path)
    336     else:
    337         msg = _get_unknown_token_message(
    338             "element", directive_token.raw_value, self.spec.elements.keys()
    339         )
--> 340         raise KatSyntaxError(
    341             msg,
    342             self.script,
    343             directive_token,
    344         )
    345 return {
    346     "token": element.directive,
    347     "name_token": element.name,
    348     "type": KatNodeType.ELEMENT,
    349     "extra_tokens": element.extra,
    350 }

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