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

File /usr/local/lib/python3.12/site-packages/finesse/model.py:2229, in Model.parse(self, text, spec)
   2210 """Parses kat script and adds the resulting objects to the model.
   2211 
   2212 Parameters
   (...)
   2225 parse_legacy_file : Parse Finesse 2 kat script file.
   2226 """
   2227 from .script import parse
-> 2229 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:154, in KatCompiler.compile(self, string, **kwargs)
    136 def compile(self, string, **kwargs):
    137     """Compile the contents of `string`.
    138 
    139     Parameters
   (...)
    152         The model compiled from reading `string`.
    153     """
--> 154     return self.compile_file(StringIO(string), **kwargs)

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

File /usr/local/lib/python3.12/site-packages/finesse/script/compiler.py:262, in KatCompiler._fill(self, value, path, **attributes)
    260     for order, argument in enumerate(value.arguments):
    261         argument_path = self.graph.item_node_name(order, path)
--> 262         self._fill(argument, argument_path)
    263         self.graph.add_edge(
    264             argument_path, path, type=KatEdgeType.ARGUMENT, order=order
    265         )
    267 return attributes

File /usr/local/lib/python3.12/site-packages/finesse/script/compiler.py:254, in KatCompiler._fill(self, value, path, **attributes)
    252 def _fill(self, value, path, **attributes):
    253     attributes = merge_attributes(
--> 254         attributes, self._item_node_attributes(value, path)
    255     )
    256     self.graph.add_node(path, **attributes)
    258     if hasattr(value, "arguments"):
    259         # 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:329, in KatCompiler._(self, element, path)
    325     else:
    326         msg = _get_unknown_token_message(
    327             "element", directive_token.raw_value, self.spec.elements.keys()
    328         )
--> 329         raise KatSyntaxError(
    330             msg,
    331             self.script,
    332             directive_token,
    333         )
    334 return {
    335     "token": element.directive,
    336     "name_token": element.name,
    337     "type": KatNodeType.ELEMENT,
    338     "extra_tokens": element.extra,
    339 }

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

File /usr/local/lib/python3.12/site-packages/finesse/model.py:2229, in Model.parse(self, text, spec)
   2210 """Parses kat script and adds the resulting objects to the model.
   2211 
   2212 Parameters
   (...)
   2225 parse_legacy_file : Parse Finesse 2 kat script file.
   2226 """
   2227 from .script import parse
-> 2229 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:154, in KatCompiler.compile(self, string, **kwargs)
    136 def compile(self, string, **kwargs):
    137     """Compile the contents of `string`.
    138 
    139     Parameters
   (...)
    152         The model compiled from reading `string`.
    153     """
--> 154     return self.compile_file(StringIO(string), **kwargs)

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

File /usr/local/lib/python3.12/site-packages/finesse/script/compiler.py:262, in KatCompiler._fill(self, value, path, **attributes)
    260     for order, argument in enumerate(value.arguments):
    261         argument_path = self.graph.item_node_name(order, path)
--> 262         self._fill(argument, argument_path)
    263         self.graph.add_edge(
    264             argument_path, path, type=KatEdgeType.ARGUMENT, order=order
    265         )
    267 return attributes

File /usr/local/lib/python3.12/site-packages/finesse/script/compiler.py:254, in KatCompiler._fill(self, value, path, **attributes)
    252 def _fill(self, value, path, **attributes):
    253     attributes = merge_attributes(
--> 254         attributes, self._item_node_attributes(value, path)
    255     )
    256     self.graph.add_node(path, **attributes)
    258     if hasattr(value, "arguments"):
    259         # 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:329, in KatCompiler._(self, element, path)
    325     else:
    326         msg = _get_unknown_token_message(
    327             "element", directive_token.raw_value, self.spec.elements.keys()
    328         )
--> 329         raise KatSyntaxError(
    330             msg,
    331             self.script,
    332             directive_token,
    333         )
    334 return {
    335     "token": element.directive,
    336     "name_token": element.name,
    337     "type": KatNodeType.ELEMENT,
    338     "extra_tokens": element.extra,
    339 }

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