labscript-suite / runviewer

π—Ώπ˜‚π—»π˜ƒπ—Άπ—²π˜„π—²π—Ώ is a graphical interface for visualising hardware-timed experiments composed using the 𝘭𝘒𝘣𝘴𝘀𝘳π˜ͺ𝘱𝘡 𝘴𝘢π˜ͺ𝘡𝘦.
http://labscriptsuite.org
BSD 2-Clause "Simplified" License
2 stars 39 forks source link

Tooltip should show line number from experiment logic file #17

Open philipstarkey opened 6 years ago

philipstarkey commented 6 years ago

Original report (archived issue) by Philip Starkey (Bitbucket: pstarkey, GitHub: philipstarkey).


I've just had an idea to create mapping between each point in a runviewer trace, and the line number of the experiment logic python file that generated that point. That way, you could easily identify which bit of your experiment logic Python code was responsible for generating a particular feature you are seeing.

This probably should be implemented as part of the next major labscript version (and not before).

I probably don't suggest saving this information along side every hardware instruction, but rather store a separate table (or tables) in much the same way we do for markers and other metadata displayed in runviewer.

Some ideas for how to access this information are here and probably I would just suggest we put it in all of the labscript functions we expect to be called (that is, we want to know where the channel.method() was called, and not say where the wrapper function make_BEC was called and also not where Output.add_instruction() was called, which probably prohibits putting it inside the method of that name).

philipstarkey commented 6 years ago

Original comment by Chris Billington (Bitbucket: cbillington, GitHub: chrisjbillington).


This is the __init__ method of the Instruction class from when I was playing with possible major changes to labscript:

#!python

class Instruction(HasParent):
    @enforce_phase(phase.ADD_INSTRUCTIONS)
    def __init__(self, parent, t, _inst_depth=1, **kwargs):
        """Base instruction class. Has an initial time, and that's about it.
        _inst_depth is the stack depth of functions that are wrappers around
        instantiating Instructions. All such functions (including the __init__
        method of subclasses of Instruction) should accept an _inst_depth=1
        keyword argument, and should pass inst_depth=_inst_depth+1 to the
        function they are wrapping (or the __init__ method of the Instruction
        class they are subclassing), in order for the traceback-making code to
        figure out where in the stack user code ends and labscript code
        begins. This is so that we can raise tracebacks that end at the line
        of user code that resulted in creating the instruction (internal
        labscript tracebacks, unless labscript itself has crashed, are not
        useful)."""
        super().__init__(parent, **kwargs)
        self.t = t
        self.parent.add_instruction(self)
        self.pseudoclock = parent.pseudoclock

        # Timing details to be computed during processing:
        self.relative_t = None
        self.quantised_t = None

        # For giving the user a traceback if an error regarding this
        # instruction is found during later processing:
        self.traceback = ''.join(traceback.format_stack()[:-_inst_depth])

        # Count how many instructions there are and save which number we are:
        self.instruction_number = self.parent.shot.total_instructions
        self.parent.shot.total_instructions += 1

You can see it saves the traceback as a string, intended for showing tracebacks during errors. There's a bit of work to do this sensibly since Instruction will have subclasses, and you don't want it to store merely the line number or traceback of the subclass's __init__ method - you need to keep a counter to know how many stack frames up the user's actual code is, so that's what the _inst_depth variable is about.

Could easily save line numbers too, using the insect module as you mentioned (rather than trying to parse it out of the traceback), though strictly speaking a traceback is more general since the same line number could be called from multiple locations if you are re-using a function. Or could include a line number and the full traceback so that the user could see just one at a glance and then only read the whole traceback if they want to.

Definitely something to include in a way accessible to runmanager!