22import json
33import sys
44import os
5+ from pathlib import Path
6+ from pprint import pformat
57
68import datetime
79import logging
@@ -108,7 +110,6 @@ class Terminal(QtWidgets.QMainWindow):
108110 node (:class:`~.networking.Net_Node`): Our Net_Node we use to communicate with our main networking object
109111 networking (:class:`~.networking.Terminal_Station`): Our networking object to communicate with the outside world
110112 subjects (dict): A dictionary mapping subject ID to :class:`~.subject.Subject` object.
111- pilots (dict): A dictionary mapping pilot ID to a list of its subjects, its IP, and any other pilot attributes.
112113 layout (:class:`QtWidgets.QGridLayout`): Layout used to organize widgets
113114 control_panel (:class:`~.gui.Control_Panel`): Control Panel to manage pilots and subjects
114115 data_panel (:class:`~.plots.Plot_Widget`): Plots for each pilot and subject.
@@ -130,7 +131,6 @@ def __init__(self):
130131
131132 # data
132133 self .subjects = {} # Dict of our open subject objects
133- self .pilots = None
134134
135135 # gui
136136 self .layout = None
@@ -141,13 +141,12 @@ def __init__(self):
141141 self .data_panel = None
142142 self .logo = None
143143
144+ # property private attributes
145+ self ._pilots = None
146+
144147 # logging
145148 self .logger = init_logger (self )
146149
147- # Load pilots db as ordered dictionary
148- with open (prefs .get ('PILOT_DB' )) as pilot_file :
149- self .pilots = json .load (pilot_file , object_pairs_hook = odict )
150-
151150 # Listen dictionary - which methods to call for different messages
152151 # Methods are spawned in new threads using handle_message
153152 self .listens = {
@@ -378,6 +377,93 @@ def reset_ui(self):
378377 self .setCentralWidget (self .widget )
379378 self .initUI ()
380379
380+ ################
381+ # Properties
382+
383+ @property
384+ def pilots (self ) -> odict :
385+ """
386+ A dictionary mapping pilot ID to its attributes, including a list of its subjects assigned to it, its IP, etc.
387+
388+ Returns:
389+ dict: like ``self.pilots['pilot_id'] = {'subjects': ['subject_0', 'subject_1'], 'ip': '192.168.0.101'}``
390+ """
391+
392+ # try to load, if none exists make one
393+ if self ._pilots is None :
394+
395+ pilot_db_fn = Path (prefs .get ('PILOT_DB' ))
396+
397+ # if pilot file doesn't exist, make blank one
398+ if not pilot_db_fn .exists ():
399+ self .logger .warning (f'No pilot_db.json file was found at { pilot_db_fn } , creating a new one' )
400+ self ._pilots = odict ()
401+ with open (pilot_db_fn , 'w' ) as pilot_file :
402+ json .dump (self ._pilots , pilot_file )
403+
404+ # otherwise, try to load it
405+ else :
406+ try :
407+ # Load pilots db as ordered dictionary
408+ with open (pilot_db_fn , 'r' ) as pilot_file :
409+ self ._pilots = json .load (pilot_file , object_pairs_hook = odict )
410+ self .logger .info (f'successfully loaded pilot_db.json file from { pilot_db_fn } ' )
411+ self .logger .debug (pformat (self ._pilots ))
412+ except Exception as e :
413+ self .logger .exception ((f"Exception opening pilot_db.json file at { pilot_db_fn } , got exception: { e } .\n " ,
414+ "Not proceeding to prevent possibly overwriting corrupt pilot_db.file" ))
415+ raise e
416+
417+ return self ._pilots
418+
419+
420+ @property
421+ def protocols (self ) -> list :
422+ """
423+ List of protocol names available in ``PROTOCOLDIR``
424+
425+ Returns:
426+ list: list of protocol names in ``prefs.get('PROTOCOLDIR')``
427+ """
428+ # get list of protocol files
429+ protocols = os .listdir (prefs .get ('PROTOCOLDIR' ))
430+ protocols = [os .path .splitext (p )[0 ] for p in protocols if p .endswith ('.json' )]
431+ return protocols
432+
433+ @property
434+ def subject_protocols (self ) -> dict :
435+ """
436+
437+ Returns:
438+ subject_protocols (dict): a dictionary of subjects: [protocol, step]
439+ """
440+ # get subjects and current protocols
441+ subjects = self .subject_list
442+ subjects_protocols = {}
443+ for subject in subjects :
444+ if subject not in self .subjects .keys ():
445+ self .subjects [subject ] = Subject (subject )
446+
447+ subjects_protocols [subject ] = [self .subjects [subject ].protocol_name , self .subjects [subject ].step ]
448+
449+ return subjects_protocols
450+
451+ @property
452+ def subject_list (self ) -> list :
453+ """
454+ Get a list of all subject IDs
455+
456+ Returns:
457+ list: list of all subject IDs present in :attr:`.Terminal.pilots`
458+ """
459+ subjects = []
460+ for pilot , vals in self .pilots .items ():
461+ subjects .extend (vals ['subjects' ])
462+
463+ # use sets to get a unique list
464+ subjects = list (set (subjects ))
465+
466+ return subjects
381467
382468 ##########################3
383469 # Listens & inter-object methods
@@ -626,23 +712,6 @@ def new_protocol(self):
626712 with open (protocol_file , 'w' ) as pfile_open :
627713 json .dump (save_steps , pfile_open , indent = 4 , separators = (',' , ': ' ), sort_keys = True )
628714
629- @property
630- def subject_list (self ):
631- """
632- Get a list of all subject IDs
633-
634- Returns:
635- list: list of all subject IDs present in :attr:`.Terminal.pilots`
636- """
637- subjects = []
638- for pilot , vals in self .pilots .items ():
639- subjects .extend (vals ['subjects' ])
640-
641- # use sets to get a unique list
642- subjects = list (set (subjects ))
643-
644- return subjects
645-
646715 def subject_weights (self ):
647716 """
648717 Gets recent weights from all :attr:`~.Terminal.subjects` and
@@ -692,36 +761,6 @@ def update_protocols(self):
692761 msgbox .setDetailedText ("\n " .join (sorted (updated_subjects )))
693762 msgbox .exec_ ()
694763
695- @property
696- def protocols (self ):
697- """
698- Returns:
699- list: list of protocol files in ``prefs.get('PROTOCOLDIR')``
700- """
701- # get list of protocol files
702- protocols = os .listdir (prefs .get ('PROTOCOLDIR' ))
703- protocols = [os .path .splitext (p )[0 ] for p in protocols if p .endswith ('.json' )]
704- return protocols
705-
706- @property
707- def subject_protocols (self ):
708- """
709-
710- Returns:
711- subject_protocols (dict): a dictionary of subjects: [protocol, step]
712- """
713- # get subjects and current protocols
714- subjects = self .subject_list
715- subjects_protocols = {}
716- for subject in subjects :
717- if subject not in self .subjects .keys ():
718- self .subjects [subject ] = Subject (subject )
719-
720- subjects_protocols [subject ] = [self .subjects [subject ].protocol_name , self .subjects [subject ].step ]
721-
722- return subjects_protocols
723-
724-
725764 def reassign_protocols (self ):
726765 """
727766 Batch reassign protocols and steps.
0 commit comments