22import json
33import sys
44import os
5+ from pathlib import Path
56
67import datetime
78import logging
@@ -108,7 +109,6 @@ class Terminal(QtWidgets.QMainWindow):
108109 node (:class:`~.networking.Net_Node`): Our Net_Node we use to communicate with our main networking object
109110 networking (:class:`~.networking.Terminal_Station`): Our networking object to communicate with the outside world
110111 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.
112112 layout (:class:`QtWidgets.QGridLayout`): Layout used to organize widgets
113113 control_panel (:class:`~.gui.Control_Panel`): Control Panel to manage pilots and subjects
114114 data_panel (:class:`~.plots.Plot_Widget`): Plots for each pilot and subject.
@@ -130,7 +130,6 @@ def __init__(self):
130130
131131 # data
132132 self .subjects = {} # Dict of our open subject objects
133- self .pilots = None
134133
135134 # gui
136135 self .layout = None
@@ -141,13 +140,12 @@ def __init__(self):
141140 self .data_panel = None
142141 self .logo = None
143142
143+ # property private attributes
144+ self ._pilots = None
145+
144146 # logging
145147 self .logger = init_logger (self )
146148
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-
151149 # Listen dictionary - which methods to call for different messages
152150 # Methods are spawned in new threads using handle_message
153151 self .listens = {
@@ -378,6 +376,91 @@ def reset_ui(self):
378376 self .setCentralWidget (self .widget )
379377 self .initUI ()
380378
379+ ################
380+ # Properties
381+
382+ @property
383+ def pilots (self ) -> odict :
384+ """
385+ A dictionary mapping pilot ID to its attributes, including a list of its subjects assigned to it, its IP, etc.
386+
387+ Returns:
388+ dict: like ``self.pilots['pilot_id'] = {'subjects': ['subject_0', 'subject_1'], 'ip': '192.168.0.101'}``
389+ """
390+
391+ # try to load, if none exists make one
392+ if self ._pilots is None :
393+
394+ pilot_db_fn = Path (prefs .get ('PILOT_DB' ))
395+
396+ # if pilot file doesn't exist, make blank one
397+ if not pilot_db_fn .exists ():
398+ self .logger .warning (f'No pilot_db.json file was found at { pilot_db_fn } , creating a new one' )
399+ self ._pilots = odict ()
400+ with open (pilot_db_fn , 'w' ) as pilot_file :
401+ json .dump (self ._pilots , pilot_file )
402+
403+ # otherwise, try to load it
404+ else :
405+ try :
406+ # Load pilots db as ordered dictionary
407+ with open (pilot_db_fn , 'r' ) as pilot_file :
408+ self ._pilots = json .load (pilot_file , object_pairs_hook = odict )
409+ except Exception as e :
410+ self .logger .exception ((f"Exception opening pilot_db.json file at { pilot_db_fn } , got exception: { e } .\n " ,
411+ "Not proceeding to prevent possibly overwriting corrupt pilot_db.file" ))
412+ raise e
413+
414+ return self ._pilots
415+
416+
417+ @property
418+ def protocols (self ) -> list :
419+ """
420+ List of protocol names available in ``PROTOCOLDIR``
421+
422+ Returns:
423+ list: list of protocol names in ``prefs.get('PROTOCOLDIR')``
424+ """
425+ # get list of protocol files
426+ protocols = os .listdir (prefs .get ('PROTOCOLDIR' ))
427+ protocols = [os .path .splitext (p )[0 ] for p in protocols if p .endswith ('.json' )]
428+ return protocols
429+
430+ @property
431+ def subject_protocols (self ) -> dict :
432+ """
433+
434+ Returns:
435+ subject_protocols (dict): a dictionary of subjects: [protocol, step]
436+ """
437+ # get subjects and current protocols
438+ subjects = self .subject_list
439+ subjects_protocols = {}
440+ for subject in subjects :
441+ if subject not in self .subjects .keys ():
442+ self .subjects [subject ] = Subject (subject )
443+
444+ subjects_protocols [subject ] = [self .subjects [subject ].protocol_name , self .subjects [subject ].step ]
445+
446+ return subjects_protocols
447+
448+ @property
449+ def subject_list (self ) -> list :
450+ """
451+ Get a list of all subject IDs
452+
453+ Returns:
454+ list: list of all subject IDs present in :attr:`.Terminal.pilots`
455+ """
456+ subjects = []
457+ for pilot , vals in self .pilots .items ():
458+ subjects .extend (vals ['subjects' ])
459+
460+ # use sets to get a unique list
461+ subjects = list (set (subjects ))
462+
463+ return subjects
381464
382465 ##########################3
383466 # Listens & inter-object methods
@@ -626,23 +709,6 @@ def new_protocol(self):
626709 with open (protocol_file , 'w' ) as pfile_open :
627710 json .dump (save_steps , pfile_open , indent = 4 , separators = (',' , ': ' ), sort_keys = True )
628711
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-
646712 def subject_weights (self ):
647713 """
648714 Gets recent weights from all :attr:`~.Terminal.subjects` and
@@ -692,36 +758,6 @@ def update_protocols(self):
692758 msgbox .setDetailedText ("\n " .join (sorted (updated_subjects )))
693759 msgbox .exec_ ()
694760
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-
725761 def reassign_protocols (self ):
726762 """
727763 Batch reassign protocols and steps.
0 commit comments