Skip to content

Commit

Permalink
Merged latest code
Browse files Browse the repository at this point in the history
  • Loading branch information
lawhead committed Nov 11, 2020
2 parents facb4df + 76942f6 commit 5045dbf
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 12 deletions.
3 changes: 3 additions & 0 deletions bci_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ def bci_main(parameter_location: str, user: str, exp_type: int, mode: str, exper
parameters['parameter_location'] = parameter_location
if parameter_location != DEFAULT_PARAMETERS_PATH:
parameters.save()
default_params = load_json_parameters(DEFAULT_PARAMETERS_PATH, value_cast=True)
if parameters.add_missing_items(default_params):
raise Exception("Parameters file out of date.")

# update our parameters file with system related information
sys_info = get_system_info()
Expand Down
51 changes: 41 additions & 10 deletions bcipy/gui/mode/RSVPKeyboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,54 @@ def __init__(self, *args, **kwargs):
self.event_started = False
self.parameter_location = DEFAULT_PARAMETERS_PATH

self.parameters = load_json_parameters(
self.parameter_location, value_cast=True)
self.parameters = load_json_parameters(self.parameter_location,
value_cast=True)
self.task_colors = itertools.cycle(
['Tomato', 'orange', 'MediumTurquoise', 'MediumSeaGreen', 'MediumPurple', 'Moccasin'])

# This is set in the build_inputs method that is called automatically when using show_gui
self.user_input = None

def set_parameter_location(self, path: str) -> None:
"""Sets the parameter_location to the given path. Reloads the parameters
and updates any GUI widgets that are populated based on these params."""
self.parameter_location = path
self.parameters = load_json_parameters(self.parameter_location,
value_cast=True)
# update GUI options
if self.user_input:
self.update_user_list()

def select_parameters(self) -> None:
"""Select Parameters.
Opens a dialog to select the parameters.json configuration to use.
"""

response = self.get_filename_dialog(message='Select parameters file', file_type='JSON files (*.json)')
response = self.get_filename_dialog(message='Select parameters file',
file_type='JSON files (*.json)')
if response:
self.parameter_location = response
self.set_parameter_location(response)
# If outdated, prompt to merge with the current defaults
default_parameters = load_json_parameters(DEFAULT_PARAMETERS_PATH,
value_cast=True)
if self.parameters.add_missing_items(default_parameters):
save_response = self.throw_alert_message(
title='BciPy Alert',
message=
'The selected parameters file is out of date. Would you like to update it with the latest options?',
message_type=AlertMessageType.INFO,
okay_or_cancel=True)

if save_response == AlertResponse.OK.value:
self.parameters.save()

def edit_parameters(self) -> None:
"""Edit Parameters.
Prompts for a parameters.json file to use. If the default parameters are selected, a copy is used.
Note that any edits to the parameters file will not be applied to this GUI until the parameters
are reloaded.
"""
if self.parameter_location == DEFAULT_PARAMETERS_PATH:
# Don't allow the user to overwrite the defaults
Expand Down Expand Up @@ -206,24 +232,29 @@ def build_buttons(self) -> None:
size=[btn_refresh_width, command_btn_height], background_color='white',
action=self.refresh)

def update_user_list(self) -> None:
"""Updates the user_input combo box with a list of user ids based on the
data directory configured in the current parameters."""

self.user_input.clear()
self.user_input.addItem(RSVPKeyboard.default_text)
self.user_input.addItems(self.load_items_from_txt())

def build_inputs(self) -> None:
"""Build Inputs.
Build all inputs needed for RSVPKeyboard.
"""
items = self.load_items_from_txt()

# add default text for editting at the beginning
items.insert(0, RSVPKeyboard.default_text)

self.user_input = self.add_combobox(
position=[75, 150],
size=[280, 40],
items=items,
items=[],
editable=True,
background_color='white',
text_color='black')

self.update_user_list()

def build_images(self) -> None:
"""Build Images.
Expand Down
16 changes: 16 additions & 0 deletions bcipy/helpers/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,19 @@ def save(self, directory: str = None, name: str = None):
with open(path, 'w', encoding='utf-8') as json_file:
dump(dict(self.entries()), json_file, ensure_ascii=False, indent=2)
return str(path)

def add_missing_items(self, parameters) -> bool:
"""Given another Parameters instance, add any items that are not already
present. Existing items will not be updated.
parameters: Parameters - object from which to add parameters.
Returns bool indicating whether or not any new items were added.
"""
updated = False
existing_keys = self.keys()
for key, val in parameters.entries():
if key not in existing_keys:
self.add_entry(key, val)
updated = True
return updated
37 changes: 36 additions & 1 deletion bcipy/helpers/tests/test_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,9 @@ def test_check_entry(self):

def test_alternate_constructor(self):
"""Test alternate constructor from cast values"""
parameters = Parameters.from_cast_values(myint=1, mybool=True, mystr="Testing")
parameters = Parameters.from_cast_values(myint=1,
mybool=True,
mystr="Testing")
self.assertTrue(parameters.cast_values)
self.assertEqual(parameters['myint'], 1)
self.assertEqual(parameters['mybool'], True)
Expand All @@ -440,5 +442,38 @@ def test_alternate_constructor(self):
self.assertEqual(parameters['mybool']['value'], 'true')
self.assertEqual(parameters['mystr']['value'], 'Testing')

def test_add_missing(self):
"""Test add_missing_items"""
entry1 = {
"value": "8000",
"section": "acquisition",
"readableName": "Acquisition Port",
"helpTip": "",
"recommended_values": "",
"type": "int"
}
entry2 = {
"value": "LSL",
"section": "acquisition",
"readableName": "Acquisition Device",
"helpTip": "",
"recommended_values": ["LSL", "DSI"],
"type": "str"
}
{"acq_port": entry1, "acq_device": entry2}
parameters = Parameters(source=None)
parameters.load({"acq_port": entry1})

new_params = Parameters(source=None)
new_params.load({"acq_port": entry1, "acq_device": entry2})

self.assertFalse('acq_device' in parameters.keys())
self.assertTrue(parameters.add_missing_items(new_params))
self.assertTrue('acq_device' in parameters.keys())

self.assertFalse(parameters.add_missing_items(new_params),
"Only new parameters should be added.")


if __name__ == '__main__':
unittest.main()
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ wxPython==4.0.1
docker==2.6.1
construct==2.8.14
mne==0.17.0
PsychoPy==2020.2.4.post1
opencv_python==4.1.0.25
PsychoPy==2020.2.5
pyglet==1.5.8
numpy==1.19.2
sounddevice==0.4.1
Expand Down

0 comments on commit 5045dbf

Please sign in to comment.