Jsonify lens-shading as lists
This commit is contained in:
parent
756f18d853
commit
354524de64
1 changed files with 30 additions and 51 deletions
|
|
@ -4,8 +4,10 @@ import errno
|
||||||
import logging
|
import logging
|
||||||
import shutil
|
import shutil
|
||||||
import copy
|
import copy
|
||||||
|
import numpy as np
|
||||||
from fractions import Fraction
|
from fractions import Fraction
|
||||||
from collections import abc
|
|
||||||
|
from .utilities import recursively_apply
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Attributes:
|
Attributes:
|
||||||
|
|
@ -18,7 +20,7 @@ Attributes:
|
||||||
# HANDLE THE DEFAULT CONFIGURATION FILE
|
# HANDLE THE DEFAULT CONFIGURATION FILE
|
||||||
|
|
||||||
HERE = os.path.abspath(os.path.dirname(__file__))
|
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||||
DEFAULT_CONFIG_PATH = os.path.join(HERE, 'microscope_settings.default.yaml')
|
DEFAULT_CONFIG_PATH = os.path.join(HERE, "microscope_settings.default.yaml")
|
||||||
|
|
||||||
USER_CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".openflexure")
|
USER_CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".openflexure")
|
||||||
USER_CONFIG_FILE = os.path.join(USER_CONFIG_DIR, "microscope_settings.yaml")
|
USER_CONFIG_FILE = os.path.join(USER_CONFIG_DIR, "microscope_settings.yaml")
|
||||||
|
|
@ -26,7 +28,7 @@ USER_CONFIG_FILE = os.path.join(USER_CONFIG_DIR, "microscope_settings.yaml")
|
||||||
USER_CONFIG_FILE_OLD = os.path.join(USER_CONFIG_DIR, "microscoperc.yaml")
|
USER_CONFIG_FILE_OLD = os.path.join(USER_CONFIG_DIR, "microscoperc.yaml")
|
||||||
|
|
||||||
# Load the default config
|
# Load the default config
|
||||||
with open(DEFAULT_CONFIG_PATH, 'r') as default_rc:
|
with open(DEFAULT_CONFIG_PATH, "r") as default_rc:
|
||||||
DEFAULT_CONFIG = default_rc.read()
|
DEFAULT_CONFIG = default_rc.read()
|
||||||
|
|
||||||
# HANDLE CUSTOM YAML PARSING
|
# HANDLE CUSTOM YAML PARSING
|
||||||
|
|
@ -36,76 +38,51 @@ def construct_yaml_bool(self, node):
|
||||||
YAML otherwise caused grief for picamera properties where 'off' is a valid string value.
|
YAML otherwise caused grief for picamera properties where 'off' is a valid string value.
|
||||||
"""
|
"""
|
||||||
override_bool_values = {
|
override_bool_values = {
|
||||||
'yes': True,
|
"yes": True,
|
||||||
'no': False,
|
"no": False,
|
||||||
'true': True,
|
"true": True,
|
||||||
'false': False,
|
"false": False,
|
||||||
'on': 'on',
|
"on": "on",
|
||||||
'off': 'off',
|
"off": "off",
|
||||||
}
|
}
|
||||||
value = self.construct_scalar(node)
|
value = self.construct_scalar(node)
|
||||||
return override_bool_values[value.lower()]
|
return override_bool_values[value.lower()]
|
||||||
|
|
||||||
|
|
||||||
yaml.Loader.add_constructor(u'tag:yaml.org,2002:bool', construct_yaml_bool)
|
yaml.Loader.add_constructor(u"tag:yaml.org,2002:bool", construct_yaml_bool)
|
||||||
|
|
||||||
|
|
||||||
# HANDLE CONVERTING ARBITRARY CONFIG TO JSON-SAFE JSON
|
# HANDLE CONVERTING ARBITRARY CONFIG TO JSON-SAFE JSON
|
||||||
|
|
||||||
|
|
||||||
def convert_type_to_json_safe(v):
|
def convert_type_to_json_safe(v):
|
||||||
"""Make an individual attribute JSON-safe"""
|
"""Make an individual attribute JSON-safe"""
|
||||||
if isinstance(v, Fraction):
|
if isinstance(v, Fraction):
|
||||||
return float(v)
|
return float(v)
|
||||||
|
elif isinstance(v, np.ndarray):
|
||||||
|
return v.tolist()
|
||||||
else:
|
else:
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
|
||||||
def recursively_apply(data, func):
|
|
||||||
"""
|
|
||||||
Recursively apply a function to a dictionary, list, array, or tuple
|
|
||||||
|
|
||||||
Args:
|
def settings_to_json(data: dict):
|
||||||
data: Input iterable data
|
|
||||||
func: Function to apply to all non-iterable values
|
|
||||||
"""
|
|
||||||
# If the object is a dictionary
|
|
||||||
if isinstance(data, abc.Mapping):
|
|
||||||
return {key: recursively_apply(val, func) for key, val in data.items()}
|
|
||||||
# If the object is iterable but NOT a dictionary or a string
|
|
||||||
elif (isinstance(data, abc.Iterable) and
|
|
||||||
not isinstance(data, abc.Mapping) and
|
|
||||||
not isinstance(data, str)):
|
|
||||||
return [recursively_apply(x, func) for x in data]
|
|
||||||
# if the object is neither a map nor iterable
|
|
||||||
else:
|
|
||||||
return func(data)
|
|
||||||
|
|
||||||
|
|
||||||
def settings_to_json(data: dict, clean_keys=True):
|
|
||||||
"""
|
"""
|
||||||
Make a copy of an input dictionary that's safe for JSON return
|
Make a copy of an input dictionary that's safe for JSON return
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
data: Input dictionary
|
data: Input dictionary
|
||||||
clean_keys: Modify any keys unsuitable for JSON return
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Do not overwrite original data dictionary
|
# Do not overwrite original data dictionary
|
||||||
d = copy.deepcopy(data)
|
d = copy.deepcopy(data)
|
||||||
|
|
||||||
# If we're cleaning up unsuitable keys
|
|
||||||
if clean_keys:
|
|
||||||
# Convert lens_shading_table to a bool
|
|
||||||
if 'picamera_settings' in d['camera_settings'] and 'lens_shading_table' in d['camera_settings']['picamera_settings']:
|
|
||||||
logging.debug("Bool-ifying lens_shading_table")
|
|
||||||
if d['camera_settings']['picamera_settings']['lens_shading_table'] is not None:
|
|
||||||
d['camera_settings']['picamera_settings']['lens_shading_table'] = True
|
|
||||||
|
|
||||||
return recursively_apply(d, convert_type_to_json_safe)
|
return recursively_apply(d, convert_type_to_json_safe)
|
||||||
|
|
||||||
|
|
||||||
# HANDLE BASIC LOADING AND SAVING OF YAML FILES
|
# HANDLE BASIC LOADING AND SAVING OF YAML FILES
|
||||||
|
|
||||||
|
|
||||||
def load_yaml_file(config_path) -> dict:
|
def load_yaml_file(config_path) -> dict:
|
||||||
"""
|
"""
|
||||||
Open a .yaml config file
|
Open a .yaml config file
|
||||||
|
|
@ -138,7 +115,7 @@ def save_yaml_file(config_path: str, config_dict: dict, safe: bool = False):
|
||||||
logging.info("Saving {}...".format(config_path))
|
logging.info("Saving {}...".format(config_path))
|
||||||
logging.debug(config_dict)
|
logging.debug(config_dict)
|
||||||
|
|
||||||
with open(config_path, 'w') as outfile:
|
with open(config_path, "w") as outfile:
|
||||||
if not safe:
|
if not safe:
|
||||||
yaml.dump(config_dict, outfile)
|
yaml.dump(config_dict, outfile)
|
||||||
else:
|
else:
|
||||||
|
|
@ -173,7 +150,7 @@ def initialise_file(config_path, populate: str = ""):
|
||||||
create_file(config_path)
|
create_file(config_path)
|
||||||
|
|
||||||
logging.info("Populating {}...".format(config_path))
|
logging.info("Populating {}...".format(config_path))
|
||||||
with open(config_path, 'w') as outfile:
|
with open(config_path, "w") as outfile:
|
||||||
outfile.write(populate)
|
outfile.write(populate)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -186,12 +163,13 @@ class OpenflexureSettingsFile:
|
||||||
config_path (str): Path to the config YAML file (None falls back to default location)
|
config_path (str): Path to the config YAML file (None falls back to default location)
|
||||||
expand (bool): Expand paths to valid auxillary config files.
|
expand (bool): Expand paths to valid auxillary config files.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, config_path: str = None, expand: bool = True):
|
def __init__(self, config_path: str = None, expand: bool = True):
|
||||||
global DEFAULT_CONFIG, USER_CONFIG_FILE
|
global DEFAULT_CONFIG, USER_CONFIG_FILE
|
||||||
|
|
||||||
self.expandable_keys = {
|
self.expandable_keys = {
|
||||||
'camera_settings': None,
|
"camera_settings": None,
|
||||||
'stage_settings': None
|
"stage_settings": None,
|
||||||
} #: Dictionary of keys that can be passed as a file path string and expanded automatically
|
} #: Dictionary of keys that can be passed as a file path string and expanded automatically
|
||||||
|
|
||||||
# Set arguments
|
# Set arguments
|
||||||
|
|
@ -226,10 +204,10 @@ class OpenflexureSettingsFile:
|
||||||
save_config = self.contract_config(config)
|
save_config = self.contract_config(config)
|
||||||
else:
|
else:
|
||||||
save_config = config
|
save_config = config
|
||||||
|
|
||||||
if backup:
|
if backup:
|
||||||
if os.path.isfile(self.config_path):
|
if os.path.isfile(self.config_path):
|
||||||
shutil.copyfile(self.config_path, self.config_path+".bk")
|
shutil.copyfile(self.config_path, self.config_path + ".bk")
|
||||||
|
|
||||||
logging.debug("Saving settings dictionary to disk")
|
logging.debug("Saving settings dictionary to disk")
|
||||||
save_yaml_file(self.config_path, save_config)
|
save_yaml_file(self.config_path, save_config)
|
||||||
|
|
@ -255,8 +233,7 @@ class OpenflexureSettingsFile:
|
||||||
# For each value in the raw loaded config
|
# For each value in the raw loaded config
|
||||||
for key, value in config_dict.items():
|
for key, value in config_dict.items():
|
||||||
# If it's a valid expandable parameter
|
# If it's a valid expandable parameter
|
||||||
if (key in self.expandable_keys and
|
if key in self.expandable_keys and type(value) is str:
|
||||||
type(value) is str):
|
|
||||||
|
|
||||||
logging.debug("Expanding {}".format(value))
|
logging.debug("Expanding {}".format(value))
|
||||||
|
|
||||||
|
|
@ -282,9 +259,11 @@ class OpenflexureSettingsFile:
|
||||||
# For each value in the expanded config
|
# For each value in the expanded config
|
||||||
for key, value in config_dict.items():
|
for key, value in config_dict.items():
|
||||||
# If it's a valid expandable parameter
|
# If it's a valid expandable parameter
|
||||||
if (key in self.expandable_keys and
|
if (
|
||||||
self.expandable_keys[key] is not None and
|
key in self.expandable_keys
|
||||||
type(value) is dict):
|
and self.expandable_keys[key] is not None
|
||||||
|
and type(value) is dict
|
||||||
|
):
|
||||||
|
|
||||||
logging.debug("Saving to {}".format(self.expandable_keys[key]))
|
logging.debug("Saving to {}".format(self.expandable_keys[key]))
|
||||||
# Create the file if it doesn't exist
|
# Create the file if it doesn't exist
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue