puzzlepiece.puzzle module

class puzzlepiece.puzzle.Puzzle(app=None, name='Puzzle', debug=True, bottom_buttons=True, style='Fusion', *args, **kwargs)[source]

Bases: QWidget

A container for puzzlepiece.piece.Piece objects, meant to be the main QWidget (window) of an automation application. It keeps track of the Piece objects it contains and lets them communicate.

A simple set up will look like this:

import puzzlepiece as pzp
from puzzlepiece.pieces import random_number

# Create a Qt app that will run our GUI, and the Puzzle
app = pzp.QApp()
puzzle = pzp.Puzzle(name="Basic example")

# Add Pieces to the Puzzle
puzzle.add_piece("random", random_number.Piece, row=0, column=0)

# Show the Puzzle window and execute the Qt application
puzzle.show()
app.exec()

The Qt app creation and call to exec can be skipped when running in IPython / Jupyter, but the %gui qt magic has to be used first to enable the GUI integration.

When adding multiple Piece s, the Puzzle can be used as a context manager, ensuring that any loaded APIs will be correctly unloaded in case any of the Pieces raises an exception during setup():

with Puzzle(debug=False) as puzzle:
    # Any exceptions raised in this setup context will cause the Puzzle to shut down
    # gracefully, calling handle_close() on the Pieces added so far
    puzzle.add_piece("laser", laser.Piece, row=0, column=0)
    puzzle.add_piece("stage", stage.Piece, row=1, column=0)
puzzle.show()

# Note that the Puzzle object can still be used outside of the setup context
puzzle["laser:power].set_value(10)
Parameters:
  • app – A QtApp created to contain this QWidget.

  • name – A name for the window.

  • debug (bool) – Sets the Puzzle.debug property, if True the app should launch in debug mode and Pieces shouldn’t communicate with hardware.

  • bottom_buttons (bool) – Whether the bottom buttons of the Puzzle (Tree, Export, STOP) should be shown.

  • style – A Qt style to apply to the QApplication. puzzlepiece defaults to Fusion for cross-platform consistency, and adds some tweaks to make it look better. Set to None to maintain system-specific styling.

property pieces

A PieceDict, effectively a dictionary of Piece objects. Can be used to access Pieces from within other Pieces.

You can also directly index the Puzzle object with the Piece name, or even with a Piece and a BaseParam:

# These two are equivalent
puzzle.pieces["piece_name"]
puzzle["piece_name"]

# These three are equivalent
puzzle.pieces["piece_name"].params["piece_name"]
puzzle["piece_name"]["param_name"]
puzzle["piece_name:param_name"]

The valid keys for indexing a Puzzle object are available when autocompleting the key in IPython.

property globals

A puzzlepiece.puzzle.Globals object, effectively a dictionary, can be used for API modules that need to be shared by multiple Pieces.

See puzzlepiece.puzzle.Globals.require() and puzzlepiece.puzzle.Globals.release() for advanced use.

property debug

A bool flag set on Puzzle creation. Pieces should act in debug mode if True.

add_piece(name, piece, row, column, rowspan=1, colspan=1, param_defaults=None)[source]

Adds a Piece to the grid layout, and registers it with the Puzzle.

Parameters:
  • name – Identifying string for the Piece.

  • piece – A Piece object or a class defining one (which will be automatically instantiated).

  • row – Row index for the grid layout.

  • column – Column index for the grid layout.

  • rowspan – Height in rows.

  • colspan – Width in columns.

  • param_defaults – An optional dictionary of default param values. These will be set without calling the corresponding param setters or changed signals.

Return type:

puzzlepiece.piece.Piece

replace_piece(name, new_piece)[source]

Replace a named Piece with a new one. Can be combined with importlib.reload to do live development on Pieces.

This method is experimental and can sometimes fail. It’s useful for development, but shouldn’t really be used in production applications.

Parameters:
  • name – Name of the Piece to be replaced.

  • piece – A Piece object or a class defining one (which will be automatically instantiated).

add_folder(row, column, rowspan=1, colspan=1)[source]

Adds a tabbed Folder to the grid layout, and returns it.

Parameters:
  • row – Row index for the grid layout.

  • column – Column index for the grid layout.

  • rowspan – Height in rows.

  • column – Width in columns.

Return type:

puzzlepiece.puzzle.Folder

register_piece(name, piece)[source]

Registers a Piece object with the Puzzle. This is done by default when a Piece is added with add_piece(), puzzlepiece.puzzle.Folder.add_piece(), or puzzlepiece.puzzle.Grid.add_piece(), so this method should rarely be called manually.

process_events()[source]

Forces the QApplication to process events that happened while a callback was executing. Can for example update plots while a long process is running, or run any keyboard shortcuts pressed while proecessing.

run_worker(worker)[source]

Add a Worker to the Puzzle’s Threadpool and runs it. See puzzlepiece.threads for more details on how to set up a Worker.

custom_excepthook(exctype, value, traceback)[source]

Override or replace this method to call a custom handler whenever an exception is raised. This will run after the defatult exception handler (sys.__excepthook__), but before a GUI alert is displayed.

run(text)[source]

Execute script commands for this Puzzle as described in puzzlepiece.parse.run().

get_values(text)[source]

Get the values from multiple params as a list.

Parameters:

text – A string of comma-separated param strings as described in puzzlepiece.parse.parse_params().

Return type:

list

record_values(text, dictionary=None)[source]

Get the values from multiple params and record them in a dictionary. Useful for storing metadata about a measurement.

Parameters:
  • text – A string of comma-separated param strings as described in puzzlepiece.parse.parse_params().

  • dictionary – If provided, this function will write the param names and values to this dictionary. Otherwise, a new one is created and returned.

Return type:

dict

puzzlepiece.puzzle.QApp(args=None)[source]

A QApplication has to be constructed before any Qt objects (including the Puzzle and the Pieces), so this is a convenient shortcut to instance the QApplication class (see https://doc.qt.io/qt-6/qapplication.html).

Only one QApplication can exist at a time, so if there is already an instance, this function returns it instead of creating a new one.

Parameters:

args – list of strings to pass as arguments when creating the QApplication

class puzzlepiece.puzzle.Folder(puzzle, *args, **kwargs)[source]

Bases: QTabWidget

A tabbed group of Piece or Grid objects within the Puzzle.

Best created with puzzlepiece.puzzle.Puzzle.add_folder().

add_piece(name, piece, param_defaults=None)[source]

Adds a Piece as a tab to this Folder, and registers it with the parent Puzzle.

Parameters:
  • name – Identifying string for the Piece.

  • piece – A Piece object or a class defining one (which will be automatically instantiated).

  • param_defaults – An optional dictionary of default param values. These will be set without calling the corresponding param setters or changed signals.

Return type:

puzzlepiece.piece.Piece

add_grid(name)[source]

Adds a Grid as a tab to this Folder.

Parameters:

name – Identifying string for the Grid.

Return type:

puzzlepiece.puzzle.Grid

class puzzlepiece.puzzle.Grid(puzzle, *args, **kwargs)[source]

Bases: QWidget

A grid layout for Piece objects. For when you need multiple Pieces within a single Folder tab.

Best created with puzzlepiece.puzzle.Puzzle.add_folder().

add_piece(name, piece, row, column, rowspan=1, colspan=1, param_defaults=None)[source]

Adds a Piece to the grid layout, and registers it with the parent Puzzle.

Parameters:
  • name – Identifying string for the Piece.

  • piece – A Piece object or a class defining one (which will be automatically instantiated).

  • row – Row index for the grid layout.

  • column – Column index for the grid layout.

  • rowspan – Height in rows.

  • colspan – Width in columns.

  • param_defaults – An optional dictionary of default param values. These will be set without calling the corresponding param setters or changed signals.

Return type:

puzzlepiece.piece.Piece

class puzzlepiece.puzzle.PieceDict[source]

Bases: object

A dictionary wrapper that enforces single-use of keys, and raises a more useful error when a Piece tries to use another Piece that hasn’t been registered.

It also allows indexing params directly by using this key format: [piece_name]:[param_name].

keys()[source]
class puzzlepiece.puzzle.Globals[source]

Bases: QObject

A dictionary wrapper used for puzzlepiece.puzzle.Puzzle.globals. It behaves like a dictionary, allowing puzzlepiece.piece.Piece objects to share device APIs with each other.

Additionally, require() and release() can be used to keep track of the Pieces using a given variable, so that the API can be loaded once and then unloaded once all the Pieces are done with it.

require(name)[source]

Register that a Piece is using the variable with a given name. This will increase an internal counter to indicate the Piece having a hold on the variable.

Returns False if this is the first time a variable is being registered (and thus setup is needed) or True if the variable has been registered already.

For example, this can be used within setup():

def setup(self):
    if not self.puzzle.globals.require('sdk'):
        # Load the SDK if not done already by a different Piece
        self.puzzle.globals['sdk'] = self.load_sdk()
Parameters:

name – a dictionary key for the required variable

Return type:

bool

release(name)[source]

Indicate that a Piece is done using the variable with a given name. This will decrease an internal counter to indicate the Piece is releasing its hold on the variable.

Returns False if the counter is non-zero (so different Pieces are still using this variable) or True if all Pieces are done with the variable (in that case the SDK can be safely shut down for example).

For example, this can be used within handle_close():

def handle_close(self):
    if self.puzzle.globals.release('sdk'):
        # Unload the SDK if all Pieces are done with it
        self.puzzle.globals['sdk'].stop()
Parameters:

name – a dictionary key for the variable being released

Return type:

bool

deleted

A Qt signal called when a Globals key is deleted. The key is passed as the argument. You can use this when multiple Pieces share the same API instance - the other Pieces can connect to this Signal and handle the API being deleted.

keys()[source]
class puzzlepiece.puzzle.PretendPuzzle[source]

Bases: object

A placeholder object used if no Puzzle is provided when creating a puzzlepiece.puzzle.Piece. Its debug attribute is always True.

debug = True
process_events()[source]

Like puzzlepiece.puzzle.Puzzle.process_events().