-
Notifications
You must be signed in to change notification settings - Fork 179
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(api): Add advanced settings endpoints to api server
Fixes #1656
- Loading branch information
Showing
6 changed files
with
218 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import json | ||
import logging | ||
from copy import copy | ||
from opentrons.config import get_config_index | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
class Setting: | ||
def __init__(self, _id, title, description, old_id=None): | ||
self.id = _id | ||
self.old_id = old_id | ||
self.title = title | ||
self.description = description | ||
|
||
def __repr__(self): | ||
return '{}: {}'.format(self.__class__, self.id) | ||
|
||
|
||
settings = [ | ||
Setting( | ||
_id='shortFixedTrash', | ||
old_id='short-fixed-trash', | ||
title='Short (55mm) fixed trash', | ||
description='Trash box is 55mm tall (rather than the 77mm default)' | ||
), | ||
Setting( | ||
_id='splitLabwareDefinitions', | ||
old_id='split-labware-def', | ||
title='New JSON labware definitions', | ||
description='JSON labware definitions with a separate def file and' | ||
' offset file for each labware' | ||
), | ||
Setting( | ||
_id='calibrateToBottom', | ||
old_id='calibrate-to-bottom', | ||
title='Calibrate to bottom', | ||
description='Calibrate using the bottom-center of well A1 for each' | ||
' labware (rather than the top-center)' | ||
), | ||
Setting( | ||
_id='deckCalibrationDots', | ||
old_id='dots-deck-type', | ||
title='Deck calibration to dots', | ||
description='Perform deck calibration to dots rather than crosses, for' | ||
' robots that do not have crosses etched on the deck' | ||
), | ||
Setting( | ||
_id='disableHomeOnBoot', | ||
old_id='disable-home-on-boot', | ||
title='Disable home on boot', | ||
description='Prevent robot from homing motors on boot' | ||
) | ||
] | ||
|
||
settings_by_id = {s.id: s for s in settings} | ||
settings_by_old_id = {s.old_id: s for s in settings} | ||
|
||
|
||
def get_adv_setting(_id: str) -> bool: | ||
_id = _clean_id(_id) | ||
s = get_all_adv_settings() | ||
return bool(s.get(_id)) | ||
|
||
|
||
def get_all_adv_settings() -> dict: | ||
settings_file = get_config_index().get('featureFlagFile') | ||
|
||
values = _read_settings_file(settings_file) | ||
for key, value in values.items(): | ||
s = copy(settings_by_id[key].__dict__) | ||
s.pop('old_id') | ||
values[key] = s | ||
values[key]['value'] = value | ||
return values | ||
|
||
|
||
def set_adv_setting(_id: str, value): | ||
_id = _clean_id(_id) | ||
settings_file = get_config_index().get('featureFlagFile') | ||
s = _read_settings_file(settings_file) | ||
s[_id] = value | ||
_write_settings_file(s, settings_file) | ||
|
||
|
||
def _clean_id(_id: str) -> str: | ||
if _id in settings_by_old_id.keys(): | ||
_id = settings_by_old_id[_id].id | ||
return _id | ||
|
||
|
||
def _read_json_file(path: str) -> dict: | ||
try: | ||
with open(path, 'r') as fd: | ||
data = json.load(fd) | ||
except FileNotFoundError: | ||
data = {} | ||
return data | ||
|
||
|
||
def _read_settings_file(settings_file: str) -> dict: | ||
# Read settings from persistent file | ||
data = _read_json_file(settings_file) | ||
all_ids = [s.id for s in settings] | ||
|
||
# If any old keys are stored in the file, replace them with the new key | ||
old_keys = settings_by_old_id.keys() | ||
if any([k in old_keys for k in data.keys()]): | ||
for v in data.keys(): | ||
if v in old_keys: | ||
new_key = settings_by_old_id.get(v).id | ||
data[new_key] = data[v] | ||
data.pop(v) | ||
_write_settings_file(data, settings_file) | ||
|
||
# If any settings do not have a key in the data, default to `False` | ||
res = {key: data.get(key, False) for key in all_ids} | ||
return res | ||
|
||
|
||
def _write_settings_file(data: dict, settings_file: str): | ||
try: | ||
with open(settings_file, 'w') as fd: | ||
json.dump(data, fd) | ||
except OSError: | ||
log.exception('Failed to write advanced settings file to: {}'.format( | ||
settings_file)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,63 +1,21 @@ | ||
import os | ||
import json | ||
from opentrons.config import get_config_index | ||
from opentrons.config import advanced_settings as advs | ||
|
||
|
||
def get_feature_flag(name: str) -> bool: | ||
settings = get_all_feature_flags() | ||
return bool(settings.get(name)) | ||
def short_fixed_trash(): | ||
return advs.get_adv_setting('shortFixedTrash') | ||
|
||
|
||
def get_all_feature_flags() -> dict: | ||
settings_file = get_config_index().get('featureFlagFile') | ||
if settings_file and os.path.exists(settings_file): | ||
with open(settings_file, 'r') as fd: | ||
settings = json.load(fd) | ||
else: | ||
settings = {} | ||
return settings | ||
def split_labware_definitions(): | ||
return advs.get_adv_setting('splitLabwareDefinitions') | ||
|
||
|
||
def set_feature_flag(name: str, value): | ||
settings_file = get_config_index().get('featureFlagFile') | ||
if os.path.exists(settings_file): | ||
with open(settings_file, 'r') as fd: | ||
settings = json.load(fd) | ||
settings[name] = value | ||
else: | ||
settings = {name: value} | ||
with open(settings_file, 'w') as fd: | ||
json.dump(settings, fd) | ||
def calibrate_to_bottom(): | ||
return advs.get_adv_setting('calibrateToBottom') | ||
|
||
|
||
# short_fixed_trash | ||
# - True ('55.0'): Old (55mm tall) fixed trash | ||
# - False: 77mm tall fixed trash | ||
# - EOL: when all short fixed trash containers have been replaced | ||
def short_fixed_trash(): return get_feature_flag('short-fixed-trash') | ||
def dots_deck_type(): | ||
return advs.get_adv_setting('deckCalibrationDots') | ||
|
||
|
||
# split_labware_definitions | ||
# - True: Use new labware definitions (See: labware_definitions.py and | ||
# serializers.py) | ||
# - False: Use sqlite db | ||
def split_labware_definitions(): return get_feature_flag('split-labware-def') | ||
|
||
|
||
# calibrate_to_bottom | ||
# - True: You must calibrate your containers to bottom | ||
# - False: Otherwise the default | ||
# will be that you calibrate to the top | ||
def calibrate_to_bottom(): return get_feature_flag('calibrate-to-bottom') | ||
|
||
|
||
# dots_deck_type | ||
# - True: The deck layout has etched "dots" | ||
# - False: The deck layout has etched "crosses" | ||
def dots_deck_type(): return get_feature_flag('dots-deck-type') | ||
|
||
|
||
# disable_home_on_boot | ||
# - True: The robot should not home the carriages on boot | ||
# - False: The robot should home the carriages on boot | ||
def disable_home_on_boot(): return get_feature_flag('disable-home-on-boot') | ||
def disable_home_on_boot(): | ||
return advs.get_adv_setting('disableHomeOnBoot') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from opentrons.server.main import init | ||
|
||
|
||
def validate_response_body(body): | ||
settings_list = body.get('settings') | ||
assert type(settings_list) == list | ||
for obj in settings_list: | ||
assert 'id' in obj, '"id" field not found in settings object' | ||
assert 'title' in obj, '"title" not found for {}'.format(obj['id']) | ||
assert 'description' in obj, '"description" not found for {}'.format( | ||
obj['id']) | ||
assert 'value' in obj, '"value" not found for {}'.format(obj['id']) | ||
|
||
|
||
async def test_get(virtual_smoothie_env, loop, test_client): | ||
app = init(loop) | ||
cli = await loop.create_task(test_client(app)) | ||
|
||
resp = await cli.get('/settings') | ||
body = await resp.json() | ||
assert resp.status == 200 | ||
validate_response_body(body) | ||
|
||
|
||
async def test_set(virtual_smoothie_env, loop, test_client): | ||
app = init(loop) | ||
cli = await loop.create_task(test_client(app)) | ||
test_id = 'disableHomeOnBoot' | ||
|
||
resp = await cli.post('/settings', json={"id": test_id, "value": True}) | ||
body = await resp.json() | ||
assert resp.status == 200 | ||
validate_response_body(body) | ||
test_setting = list( | ||
filter(lambda x: x.get('id') == test_id, body.get('settings')))[0] | ||
assert test_setting.get('value') |