Commit 7529dd89 authored by Thomas Dowrick's avatar Thomas Dowrick

Merge branch '3-add-configuration-manager' into 'master'

Resolve "Decide on preferred or recommended config file format, to enable an initial ConfigurationManager type class somewhere"

Closes #3

See merge request WEISS/SoftwareRepositories/scikit-surgerycore!1
parents 659d651e a2261436
Pipeline #568 passed with stages
in 8 minutes and 22 seconds
# -*- coding: utf-8 -*-
"""
Class to load application configuration information from a json file.
Design principles:
- All errors as Exceptions
- | Fail early in constructor, so the rest of the program never
| has an invalid instance of ConfigurationManager.
| If its constructed, its valid.
- Setter and Getter do a deepcopy, so only suitable for small config files.
- | Pass ConfigurationManager to any consumer of the data,
| its up to the consumer to know where to find the data.
"""
import json
import copy
import sksurgerycore.utilities.file_utilities as f
class ConfigurationManager:
# pylint: disable=line-too-long
""" Class to load application configuration from a json file.
For example, this might be used at the startup of an application.
:param file_name: a json file to read.
:param write_on_shutdown: if True, will write back to the same file when the destructor is called.
:param write_on_setter: if True, will write back to the same file whenever the setter is called.
:raises: All errors raised as various Exceptions.
"""
def __init__(self, file_name,
write_on_shutdown=False,
write_on_setter=False
):
""" Constructor. """
f.validate_is_file(file_name)
if write_on_shutdown or write_on_setter:
f.validate_is_writable_file(file_name)
with open(file_name, "r") as read_file:
self.config_data = json.load(read_file)
self.file_name = file_name
self.write_on_shutdown = write_on_shutdown
self.write_on_setter = write_on_setter
def __del__(self):
""" If the constructor was passed write_on_shutdown=True,
then the destructor will attempt to save back the config into
the file that it was read from.
"""
if self.write_on_shutdown:
self._save_back_to_file()
def get_copy(self):
""" Returns a copy of the data read from file.
:returns: deep copy of whatever data structure is stored internally.
"""
return copy.deepcopy(self.config_data)
def set_data(self, config_data):
""" Stores the provided data internally.
Note that: you would normally load settings from disk,
and then use get_copy() to get a copy, change some settings,
and then use set_data() to pass the data structure back in.
So, the data provided for this method should still represent
the settings you want to save, not just be a completely
arbitrary data structure.
:param config_data: data structure representing your settings.
"""
if self.write_on_setter:
self._save_back_to_file()
self.config_data = copy.deepcopy(config_data)
def _save_back_to_file(self):
""" Writes the internal data back to the filename
provided during object construction.
"""
with open(self.file_name, "w") as write_file:
json.dump(self.config_data, write_file)
# coding=utf-8
"""
Various file utilities, often calling standard
functions in the os package, but throwing
nice informative Exception messages.
"""
import os
def validate_is_file(file_name):
"""
Check if file_name is a file.
"""
if not file_name:
raise ValueError("Empty parameter file_name")
if os.path.isfile(file_name):
return True
raise ValueError('File `' + file_name + '` is not a file')
def validate_is_writable_file(file_name):
"""
Check if file_name is a writable file.
"""
validate_is_file(file_name)
if os.access(file_name, os.W_OK):
return True
raise ValueError('File `' + file_name + '` is not a writeable file.')
# -*- coding: utf-8 -*-
import pytest
import sksurgerycore.configuration.configuration_manager as cm
def test_constructor_fails_with_null_filename():
with pytest.raises(ValueError):
cm.ConfigurationManager(None)
def test_constructor_fails_with_empty_filename():
with pytest.raises(ValueError):
cm.ConfigurationManager("")
def test_constructor_with_valid_file():
manager = cm.ConfigurationManager("tests/data/FordPrefect.json")
assert manager is not None
def test_setter_getter_loop():
m = cm.ConfigurationManager("tests/data/FordPrefect.json")
d = m.get_copy()
d["researcher"]["name"] = "Ford Anglia"
m.set_data(d)
e = m.get_copy()
assert e["researcher"]["name"] == "Ford Anglia"
{"researcher": {"species": "Betelgeusian", "name": "Ford Anglia", "relatives": [{"species": "Betelgeusian", "name": "Zaphod Beeblebrox"}]}}
\ No newline at end of file
# coding=utf-8
"""
Tests for file_utilities.py
"""
import pytest
from sksurgerycore.utilities import file_utilities as f
def test_invalid_file_name_because_non_existent():
with pytest.raises(ValueError):
f.validate_is_file("/invalid/file/name")
def test_invalid_file_name_because_directory():
with pytest.raises(ValueError):
f.validate_is_file(".")
def test_valid_file_name():
result = f.validate_is_file("tests/data/FordPrefect.json")
assert result
def test_valid_writeable_file():
result = f.validate_is_writable_file("tests/data/FordPrefect.json")
assert result
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment