Skip to content

Commit 52446f8

Browse files
Merge pull request #79 from wehr-lab/pilot_db
v0.3.5 - Fixing pilot db access
2 parents 0753925 + af19d97 commit 52446f8

File tree

6 files changed

+117
-71
lines changed

6 files changed

+117
-71
lines changed

autopilot/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
__author__ = 'Jonny Saunders <[email protected]>'
2-
__version__ = '0.3.4'
2+
__version__ = '0.3.5'

autopilot/core/gui.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -274,15 +274,8 @@ def update_db(self, **kwargs):
274274
if 'state' in val.keys():
275275
del val['state']
276276

277-
try:
278-
with open(prefs.get('PILOT_DB'), 'w') as pilot_file:
279-
json.dump(self.pilots, pilot_file, indent=4, separators=(',', ': '))
280-
except NameError:
281-
try:
282-
with open('/usr/autopilot/pilot_db.json', 'w') as pilot_file:
283-
json.dump(self.pilots, pilot_file, indent=4, separators=(',', ': '))
284-
except IOError:
285-
Exception('Couldnt update pilot db!')
277+
with open(prefs.get('PILOT_DB'), 'w') as pilot_file:
278+
json.dump(self.pilots, pilot_file, indent=4, separators=(',', ': '))
286279

287280
####################################
288281
# Control Panel Widgets

autopilot/core/terminal.py

Lines changed: 92 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import json
33
import sys
44
import os
5+
from pathlib import Path
6+
from pprint import pformat
57

68
import datetime
79
import 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.

autopilot/core/utils.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
except ImportError:
88
pass
99

10+
from collections import OrderedDict as odict
1011
import json
1112
import pandas as pd
1213
from scipy.stats import linregress
@@ -165,23 +166,23 @@ def load_pilotdb(file_name=None, reverse=False):
165166
Try to load the file_db
166167
167168
Args:
168-
reverse:
169-
file_name:
169+
reverse (bool): Return inverted pilot db mapping subjects: pilots (default False)
170+
file_name (str): Path of ``pilot_db.json``, if None, use ``prefs.get('PILOT_DB')``
170171
171172
Returns:
172-
173+
:class:`collections.OrderedDict` : pilot_db.json or reversed pilot_db
173174
"""
174175

175176
if file_name is None:
176-
file_name = '/usr/autopilot/pilot_db.json'
177+
file_name = prefs.get('PILOT_DB')
177178

178179
with open(file_name) as pilot_file:
179-
pilot_db = json.load(pilot_file)
180+
pilot_db = json.load(pilot_file, object_pairs_hook=odict)
180181

181182
if reverse:
182183
# simplify pilot db
183-
pilot_db = {k: v['subjects'] for k, v in pilot_db.items()}
184-
pilot_dict = {}
184+
pilot_db = odict({k: v['subjects'] for k, v in pilot_db.items()})
185+
pilot_dict = odict()
185186
for pilot, subjectlist in pilot_db.items():
186187
for ms in subjectlist:
187188
pilot_dict[ms] = pilot

docs/changelog/v0.3.0.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
.. _changelog_v030:
22

3+
v0.3.5 (February 22, 2021)
4+
--------------------------
5+
6+
Bugfixes
7+
~~~~~~~~
8+
9+
* Very minor one, fixes to the way :class:`.Terminal` accesses the ``pilot_db.json`` file to use :attr:`.Terminal.pilots`
10+
property that makes a new pilot_db.json file if one doesn't exist, but otherwise loads the one that is found in
11+
``prefs.get('PILOT_DB')``
12+
* Reorganized :class:`.Terminal` source to group properties together & minor additions of type hinting
13+
* Fixed some bad fallback behavior looking for files in old hardcoded default directories, eg. in the ye olde
14+
:func:`.utils.get_pilotdb`
15+
316
v0.3.4 (December 13, 2020)
417
---------------------------
518

docs/notes/building.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
deployment
22
- write docs
33
- write changelog
4-
- bump version in setup.py
4+
- bump version in __init__.py
55

66
- do PR
77
- merge

0 commit comments

Comments
 (0)