ENLIGHTEN
Cross-platform desktop GUI for Wasatch Photonics spectrometers
Loading...
Searching...
No Matches
enlighten.Plugins.PluginController.PluginController Class Reference

Public Member Functions

 __init__ (self, ctl)
 
 add_copy_dataframe_to_clipboard_button (self)
 
 apply_commands (self, response)
 
 apply_overrides (self, orig_pr, response)
 
 apply_signals (self, response)
 
 button_process_callback (self)
 The user clicked the "process" button on the control panel indicating "please process the current spectra".
 
 cancel_worker (self, send_downstream=True)
 
 clear (self)
 
 clear_plugin_layout (self, layout)
 
 clear_previous_layout (self)
 
 combo_module_callback (self)
 The user just selected a different plugin.
 
 configure_gui_for_module (self, module_name)
 This may or may not be the first time this plugin has been selected, so make sure the module is loaded, instantiated and we have its configuration, then update the GUI accordingly.
 
 connected_callback (self)
 
 copy_dataframe_to_clipboard (self)
 
 create_graph_curves (self, name, graph)
 
 create_output_table (self)
 Used to hold the output Pandas table, if one is provided.
 
 create_plugins_folder (self)
 Create the plugins folder if it does not exist.
 
 disconnect (self)
 
 display_exception (self, summary, detail)
 Make it easy for plug-in authors to see exceptions when debugging their class.
 
 do_post_disconnect (self)
 
 find_all_plugins (self)
 returns a hash of PluginModuleInfo
 
 force_load_plugin (self, module_name)
 
 get_active_graph (self)
 
 get_current_configuration (self)
 
 get_current_module_info (self)
 utility #
 
 get_current_settings (self)
 
 get_plugin_fields (self)
 Used by the plugin to programmatically change fields.
 
 graph_pos_callback (self)
 The user changed the combobox indicating where the "second graph" should appear.
 
 handle_response (self, response, orig_pr=None)
 
 hide_widget (self)
 
 init_plugin_plot (self)
 
 initialize_python_path (self)
 
 populate_combobox (self, cb, items, index=0)
 
 populate_plugin_list (self)
 
 process_reading (self, processed_reading, settings, spec, manual=False)
 Processes any queued responses, then sends the new request.
 
 process_response_blocking (self, orig_pr)
 Probably a controversial method...actually freeze the ENLIGHTEN GUI until the next plugin response is available.
 
 process_responses (self)
 
 process_widgets (self, widgets, container)
 
 release_block (self, request)
 
 run_worker (self)
 
 show_plugin_graph (self, flag)
 
 start (self, ms)
 The PluginController doesn't normally have an internal event loop (it's mostly ticked by Controller.tick_status).
 
 stop (self)
 
 tick (self)
 
 update_field_visibility (self)
 
 update_visibility (self)
 Something has changed in ENLIGHTEN which might cause a plugin to need to update its visual state – perhaps a new spectrometer was connected.
 

Public Attributes

 autoload = None
 
 blocking_request = None
 
 button_process = cfu.pushButton_plugin_process
 
 button_process_callback
 
 cb_connected = cfu.checkBox_plugin_connected
 
 combo_graph_pos = cfu.comboBox_plugin_graph_pos
 
 combo_module = cfu.comboBox_plugin_module
 
 combo_module_callback
 
bool connected = False
 
 connected_callback
 
 copy_dataframe_to_clipboard = QtWidgets.QPushButton()
 
 ctl = ctl
 
 dataframe = None
 
 directory = common.get_default_data_dir()
 
bool enabled = False
 
 frame_control = cfu.frame_plugin_control
 
 frame_fields = cfu.frame_plugin_fields
 
 graph_plugin = None
 
 graph_pos_callback
 
 layout_graphs = cfu.layout_scope_capture_graphs
 
 lb_graph_pos = cfu.label_plugin_graph_pos
 
 lb_title = cfu.label_plugin_title
 
 lb_widget = cfu.label_plugin_widget
 
int max_cols = 0
 
int max_rows = 0
 
 module_infos = None
 
 module_name = None
 
 mut = QtCore.QMutex()
 
int next_request_id = 0
 
 panda_field = None
 
dict plugin_curves = {}
 
list plugin_dirs
 
list plugin_field_widgets = []
 
 plugin_fields_layout = QtWidgets.QVBoxLayout()
 
 plugin_plot = None
 
 plugin_plot_legend = self.plugin_plot.addLegend()
 
 request_queue = Queue()
 
 response_queue = Queue()
 
 table_view = None
 
 tick
 
 timer = QtCore.QTimer()
 
 update_field_visibility
 
bool use_other_graph = True
 
 use_plugin_graph = flag
 
 vlayout_fields = cfu.verticalLayout_plugin_fields
 
 worker = None
 

Static Public Attributes

str SECTION = "plugins"
 

Detailed Description

Requirements
  • NOT required:
    • auto-detect new plugins placed in watch directories while ENLIGHTEN is running
    • auto-recompile edited plugins while ENLIGHTEN is running
    • load plugins from arbitrary directories (EnlightenSpectra/plugins is fine)
GUI Logic
  • [1] when you FIRST select a plugin, it will:
    • show the unchecked cb_connected
    • load the module
    • instantiate the plugin
    • call plugin.get_configuration()
    • update the GUI to display the module
    • NOT create a worker
    • NOT start passing ProcessedReadings
  • [2] if you then select a DIFFERENT plugin (before checking Connect), it will:
    • leave cb_conenct shown but unchecked
    • cache the previous configuration
    • load the new module
    • load the new configuration
    • instantiate the plugin
    • update the GUI for the new configuration
    • NOT create a worker
    • NOT start passing ProcessedReadings
  • [3] when you finally click Connect (which is only visible when a valid plugin is selected),
    • it will disable combo_module (you can't change plugins while connected)
    • it will create a worker
    • it will start() the worker
    • the WORKER will call plugin.start() (such that any sub-processes etc are entirely within the thread)
    • the worker will run() until it receives a None (poison-pill)
    • it will show and CHECK the Enable button
  • [4] when you uncheck Enable
    • PluginController will set .enabled = False, stop sending readings to the request_queue, and ignore responses coming from response_queue
    • the worker will keep running, quietly, in the background
    • the GUI will stay configured for the connected plugin's fields
  • [5] if you uncheck Connect (whether Enabled or not)
    • it will uncheck and HIDE Enabled
    • it will send a poison-pill downstream to the worker
    • the worker will call plugin.stop()
    • the worker will close
    • it will re-enable combo_module
    • it will delete the worker object
    • you will basically be back at [1]

Notes:

  • cb_connected determines
    • whether combo_module is enabled, and worker exists
  • combo_module determines how the GUI is currently configured
Apologia

For posterity, some of the changes I made to Evan's original version were because I was trying to avoid fully destroying / shutting down previously-used plugins when changing to a new plugin; and playing with thoughts of having multiple plug-ins running at one time. I've come to accept this would be undesirable complexity at this time.

Constructor & Destructor Documentation

◆ __init__()

enlighten.Plugins.PluginController.PluginController.__init__ ( self,
ctl )

Member Function Documentation

◆ add_copy_dataframe_to_clipboard_button()

enlighten.Plugins.PluginController.PluginController.add_copy_dataframe_to_clipboard_button ( self)

◆ apply_commands()

enlighten.Plugins.PluginController.PluginController.apply_commands ( self,
response )

◆ apply_overrides()

enlighten.Plugins.PluginController.PluginController.apply_overrides ( self,
orig_pr,
response )

◆ apply_signals()

enlighten.Plugins.PluginController.PluginController.apply_signals ( self,
response )

◆ button_process_callback()

enlighten.Plugins.PluginController.PluginController.button_process_callback ( self)

The user clicked the "process" button on the control panel indicating "please process the current spectra".

◆ cancel_worker()

enlighten.Plugins.PluginController.PluginController.cancel_worker ( self,
send_downstream = True )

◆ clear()

enlighten.Plugins.PluginController.PluginController.clear ( self)

◆ clear_plugin_layout()

enlighten.Plugins.PluginController.PluginController.clear_plugin_layout ( self,
layout )

◆ clear_previous_layout()

enlighten.Plugins.PluginController.PluginController.clear_previous_layout ( self)

◆ combo_module_callback()

enlighten.Plugins.PluginController.PluginController.combo_module_callback ( self)

The user just selected a different plugin.

Don't do anything drastic at this point, just allow them to connect if a valid module was chosen.

◆ configure_gui_for_module()

enlighten.Plugins.PluginController.PluginController.configure_gui_for_module ( self,
module_name )

This may or may not be the first time this plugin has been selected, so make sure the module is loaded, instantiated and we have its configuration, then update the GUI accordingly.

Note
called by combo_module_callback

◆ connected_callback()

enlighten.Plugins.PluginController.PluginController.connected_callback ( self)

◆ copy_dataframe_to_clipboard()

enlighten.Plugins.PluginController.PluginController.copy_dataframe_to_clipboard ( self)

◆ create_graph_curves()

enlighten.Plugins.PluginController.PluginController.create_graph_curves ( self,
name,
graph )

◆ create_output_table()

enlighten.Plugins.PluginController.PluginController.create_output_table ( self)

Used to hold the output Pandas table, if one is provided.

◆ create_plugins_folder()

enlighten.Plugins.PluginController.PluginController.create_plugins_folder ( self)

Create the plugins folder if it does not exist.

◆ disconnect()

enlighten.Plugins.PluginController.PluginController.disconnect ( self)

◆ display_exception()

enlighten.Plugins.PluginController.PluginController.display_exception ( self,
summary,
detail )

Make it easy for plug-in authors to see exceptions when debugging their class.

Todo
move from QMessageBox to a custom dialog that's resizeable / larger

◆ do_post_disconnect()

enlighten.Plugins.PluginController.PluginController.do_post_disconnect ( self)

◆ find_all_plugins()

enlighten.Plugins.PluginController.PluginController.find_all_plugins ( self)

returns a hash of PluginModuleInfo

Todo
prefix name with module hierarchy, i.e. Prod.DarkNoise, Demo.NullOddBlock

◆ force_load_plugin()

enlighten.Plugins.PluginController.PluginController.force_load_plugin ( self,
module_name )

◆ get_active_graph()

enlighten.Plugins.PluginController.PluginController.get_active_graph ( self)

◆ get_current_configuration()

enlighten.Plugins.PluginController.PluginController.get_current_configuration ( self)

◆ get_current_module_info()

enlighten.Plugins.PluginController.PluginController.get_current_module_info ( self)

utility #

◆ get_current_settings()

enlighten.Plugins.PluginController.PluginController.get_current_settings ( self)

◆ get_plugin_fields()

enlighten.Plugins.PluginController.PluginController.get_plugin_fields ( self)

Used by the plugin to programmatically change fields.

◆ graph_pos_callback()

enlighten.Plugins.PluginController.PluginController.graph_pos_callback ( self)

The user changed the combobox indicating where the "second graph" should appear.

See also
Controller.populate_placeholder_scope_capture

◆ handle_response()

enlighten.Plugins.PluginController.PluginController.handle_response ( self,
response,
orig_pr = None )
Todo
split-out outputs, series into their own methods

◆ hide_widget()

enlighten.Plugins.PluginController.PluginController.hide_widget ( self)

◆ init_plugin_plot()

enlighten.Plugins.PluginController.PluginController.init_plugin_plot ( self)

◆ initialize_python_path()

enlighten.Plugins.PluginController.PluginController.initialize_python_path ( self)

◆ populate_combobox()

enlighten.Plugins.PluginController.PluginController.populate_combobox ( self,
cb,
items,
index = 0 )

◆ populate_plugin_list()

enlighten.Plugins.PluginController.PluginController.populate_plugin_list ( self)

◆ process_reading()

enlighten.Plugins.PluginController.PluginController.process_reading ( self,
processed_reading,
settings,
spec,
manual = False )

Processes any queued responses, then sends the new request.

Note that we make deep copies of both settings and the processed_reading, to minimize opportunities for bugs / exploits in plugins that could break ENLIGHTEN. This is a performance hit, but oh well.

Returns
true if new EnlightenPluginRequest successfully sent to plugin

◆ process_response_blocking()

enlighten.Plugins.PluginController.PluginController.process_response_blocking ( self,
orig_pr )

Probably a controversial method...actually freeze the ENLIGHTEN GUI until the next plugin response is available.

Enforces a hard timeout of 1sec. Probably we could do this in the background so the "GUI" doesn't free, but ...we actually don't want to process any new spectra until this is resolved.

Parameters
orig_prthe original ProcessedReading which led to this response, so we can fold response outputs into the original PR.
Returns
True if response received and processed within timeout

◆ process_responses()

enlighten.Plugins.PluginController.PluginController.process_responses ( self)

◆ process_widgets()

enlighten.Plugins.PluginController.PluginController.process_widgets ( self,
widgets,
container )

◆ release_block()

enlighten.Plugins.PluginController.PluginController.release_block ( self,
request )

◆ run_worker()

enlighten.Plugins.PluginController.PluginController.run_worker ( self)

◆ show_plugin_graph()

enlighten.Plugins.PluginController.PluginController.show_plugin_graph ( self,
flag )
Todo
it would be neat if plugins themselves could toggle self.use_other_graph, but we'd need to move existing curves between graphs/legends via self.plugin_curves

◆ start()

enlighten.Plugins.PluginController.PluginController.start ( self,
ms )

The PluginController doesn't normally have an internal event loop (it's mostly ticked by Controller.tick_status).

However, occasionally it needs events which occur in the GUI thread, so widgets can be updated. This is for that.

◆ stop()

enlighten.Plugins.PluginController.PluginController.stop ( self)

◆ tick()

enlighten.Plugins.PluginController.PluginController.tick ( self)

◆ update_field_visibility()

enlighten.Plugins.PluginController.PluginController.update_field_visibility ( self)

◆ update_visibility()

enlighten.Plugins.PluginController.PluginController.update_visibility ( self)

Something has changed in ENLIGHTEN which might cause a plugin to need to update its visual state – perhaps a new spectrometer was connected.

Member Data Documentation

◆ autoload

enlighten.Plugins.PluginController.PluginController.autoload = None

◆ blocking_request

enlighten.Plugins.PluginController.PluginController.blocking_request = None

◆ button_process

enlighten.Plugins.PluginController.PluginController.button_process = cfu.pushButton_plugin_process

◆ button_process_callback

enlighten.Plugins.PluginController.PluginController.button_process_callback

◆ cb_connected

enlighten.Plugins.PluginController.PluginController.cb_connected = cfu.checkBox_plugin_connected

◆ combo_graph_pos

enlighten.Plugins.PluginController.PluginController.combo_graph_pos = cfu.comboBox_plugin_graph_pos

◆ combo_module

enlighten.Plugins.PluginController.PluginController.combo_module = cfu.comboBox_plugin_module

◆ combo_module_callback

enlighten.Plugins.PluginController.PluginController.combo_module_callback

◆ connected

bool enlighten.Plugins.PluginController.PluginController.connected = False

◆ connected_callback

enlighten.Plugins.PluginController.PluginController.connected_callback

◆ copy_dataframe_to_clipboard

enlighten.Plugins.PluginController.PluginController.copy_dataframe_to_clipboard = QtWidgets.QPushButton()

◆ ctl

enlighten.Plugins.PluginController.PluginController.ctl = ctl

◆ dataframe

enlighten.Plugins.PluginController.PluginController.dataframe = None

◆ directory

enlighten.Plugins.PluginController.PluginController.directory = common.get_default_data_dir()

◆ enabled

enlighten.Plugins.PluginController.PluginController.enabled = False

◆ frame_control

enlighten.Plugins.PluginController.PluginController.frame_control = cfu.frame_plugin_control

◆ frame_fields

enlighten.Plugins.PluginController.PluginController.frame_fields = cfu.frame_plugin_fields

◆ graph_plugin

enlighten.Plugins.PluginController.PluginController.graph_plugin = None

◆ graph_pos_callback

enlighten.Plugins.PluginController.PluginController.graph_pos_callback

◆ layout_graphs

enlighten.Plugins.PluginController.PluginController.layout_graphs = cfu.layout_scope_capture_graphs

◆ lb_graph_pos

enlighten.Plugins.PluginController.PluginController.lb_graph_pos = cfu.label_plugin_graph_pos

◆ lb_title

enlighten.Plugins.PluginController.PluginController.lb_title = cfu.label_plugin_title

◆ lb_widget

enlighten.Plugins.PluginController.PluginController.lb_widget = cfu.label_plugin_widget

◆ max_cols

int enlighten.Plugins.PluginController.PluginController.max_cols = 0

◆ max_rows

int enlighten.Plugins.PluginController.PluginController.max_rows = 0

◆ module_infos

enlighten.Plugins.PluginController.PluginController.module_infos = None

◆ module_name

enlighten.Plugins.PluginController.PluginController.module_name = None

◆ mut

enlighten.Plugins.PluginController.PluginController.mut = QtCore.QMutex()

◆ next_request_id

int enlighten.Plugins.PluginController.PluginController.next_request_id = 0

◆ panda_field

enlighten.Plugins.PluginController.PluginController.panda_field = None

◆ plugin_curves

enlighten.Plugins.PluginController.PluginController.plugin_curves = {}

◆ plugin_dirs

list enlighten.Plugins.PluginController.PluginController.plugin_dirs
Initial value:
= [
"plugins", # (for developers running from source)
os.path.join(common.get_default_data_dir(), "plugins") # (installed EnlightenSpectra/plugins)
]

◆ plugin_field_widgets

enlighten.Plugins.PluginController.PluginController.plugin_field_widgets = []

◆ plugin_fields_layout

enlighten.Plugins.PluginController.PluginController.plugin_fields_layout = QtWidgets.QVBoxLayout()

◆ plugin_plot

enlighten.Plugins.PluginController.PluginController.plugin_plot = None

◆ plugin_plot_legend

enlighten.Plugins.PluginController.PluginController.plugin_plot_legend = self.plugin_plot.addLegend()

◆ request_queue

enlighten.Plugins.PluginController.PluginController.request_queue = Queue()

◆ response_queue

enlighten.Plugins.PluginController.PluginController.response_queue = Queue()

◆ SECTION

enlighten.Plugins.PluginController.PluginController.SECTION = "plugins"
static

◆ table_view

enlighten.Plugins.PluginController.PluginController.table_view = None

◆ tick

enlighten.Plugins.PluginController.PluginController.tick

◆ timer

enlighten.Plugins.PluginController.PluginController.timer = QtCore.QTimer()

◆ update_field_visibility

enlighten.Plugins.PluginController.PluginController.update_field_visibility

◆ use_other_graph

bool enlighten.Plugins.PluginController.PluginController.use_other_graph = True

◆ use_plugin_graph

enlighten.Plugins.PluginController.PluginController.use_plugin_graph = flag

◆ vlayout_fields

enlighten.Plugins.PluginController.PluginController.vlayout_fields = cfu.verticalLayout_plugin_fields

◆ worker

enlighten.Plugins.PluginController.PluginController.worker = None

The documentation for this class was generated from the following file: