sas.system.config package¶
Submodules¶
sas.system.config.config module¶
Configuration class - stores configuration information for SasView
If you’re looking to change a field in the config file, you should read this
Configs¶
Configs are a nightmare from the perspective of code maintainability. There are three main reasons for this:
They have a tendency to accumulate junk because people dont realise that a config item is no longer needed
It’s hard to trace the usages and types because values are loaded at runtime
Maintaining synchrony between config files and config usages is difficult, as it is the users that have control over the config files.
The Config class here attempts to resolve some of these issues in a way that preserves as many of the current uses as possible. It is a compromise between SasView’s current methods, and more standard ways of handling configurations.
Brief Outline¶
The main Config class provides a definition of the variables allowed in a config file, along with their default values. This class is used to generate a schema that determines how config files are read. Only a few types of variable are allowed
bool
int
float
str
Homogeneous lists of the above, to 10 levels of depth
None and empty list (please try to avoid)
Other types will throw an error at runtime when the schema is created.
None types and empty lists have no type information at runtime, so the schema cannot check/coerce the type of config variables when they are loaded. It is best to avoid having these as default values if possible.
The presence of a config file is not necessary for the functioning of the config system, only for making changes that differ from the default values.
What Belongs in a Config¶
Things that do belong:
Program settings that are configurable by users through the GUI
Program settings that have no GUI editor, but that some advanced users might want to set manually with a text editor
Settings that control developer tools, e.g. debug modes
Very little else
Things that don’t belong, but were previously in the config:
dynamic content, i.e. values that are modified programmatically, this includes variables that are defined in terms of other variables, but otherwise don’t change
Paths to resources within sasview (use importlib.resources instead)
Blocks of data that won’t be modified by the user and used primarily by single class - e.g. the text for a message
Large blocks of text in general
Making Changes to the Config Class¶
As users have their own copy of the sasview configuration, deletions, name changes, default value changes, and variable type changes often constitute a breaking change from the perspective of version control. The users locally stored config will, in general, not be backwards compatible with the new config. Extreme caution should be exercised - when changing the config, don’t just think about the problem at hand, but about the future maintainability of SasView in general.
Adding to the Config class: Before adding a variable, think about whether it might more properly belong somewhere else, perhaps in the web or legal classes in the system package. Remember that config variables are accessed across the whole of sasview and that names need to be suitably descriptive.
Deleting from the Config class: Currently (02/09/2022) the consequences of providing an entry in a config file that is not properly reflected in the Config class is a error. To ease backward compatibility, it is possible to disable the errors for a deleted class member by adding their name to the _deleted_attributes list. The suggested deletion process would be
`
[-] self.my_variable = 10
[+] self._deleted_attributes.append("my_variable")
`
At major releases, additions to _deleted_attributes should be removed.
Other Design Decisions made for the Config Class¶
The Config class cannot be dynamically modified, this prevents the config from having fields that are unspecified in the base class, and makes it so that all usages of fields can be automatically tracked.
Subclassing of Config is also disabled for similar reasons.
I have opted not to use frozen dataclasses at this time because, as they currently work, the behaviour would make creating different configs difficult.
- class sas.system.config.config.Config¶
Bases:
ConfigBase
- __doc__ = None¶
- __init__()¶
- __module__ = 'sas.system.config.config'¶
sas.system.config.config_meta module¶
- class sas.system.config.config_meta.ConfigBase¶
Bases:
object
Base class for Config, keep the definition of config variables and workings as separate as possible
- __annotations__ = {}¶
- __dict__ = mappingproxy({'__module__': 'sas.system.config.config_meta', '__doc__': ' Base class for Config, keep the definition of config variables and workings as separate as possible ', '__init__': <function ConfigBase.__init__>, 'defaults': <property object>, 'config_filename': <function ConfigBase.config_filename>, 'finalise': <function ConfigBase.finalise>, 'update': <function ConfigBase.update>, 'save': <function ConfigBase.save>, 'override_with_defaults': <function ConfigBase.override_with_defaults>, 'save_to_file_object': <function ConfigBase.save_to_file_object>, 'load': <function ConfigBase.load>, 'load_from_file_object': <function ConfigBase.load_from_file_object>, '_state_copy': <function ConfigBase._state_copy>, '_generate_schema': <function ConfigBase._generate_schema>, '__setattr__': <function ConfigBase.__setattr__>, 'validate': <function ConfigBase.validate>, '__dict__': <attribute '__dict__' of 'ConfigBase' objects>, '__weakref__': <attribute '__weakref__' of 'ConfigBase' objects>, '__annotations__': {'_schema': 'Dict[str, SchemaElement]', '_defaults': 'Dict[str, SchemaElement]', '_deleted_attributes': 'List[str]', '_bad_entries': 'Dict[str, Any]'}})¶
- __doc__ = ' Base class for Config, keep the definition of config variables and workings as separate as possible '¶
- __init__()¶
- __module__ = 'sas.system.config.config_meta'¶
- __setattr__(key, value)¶
Implement setattr(self, name, value).
- __weakref__¶
list of weak references to the object
- _generate_schema() Dict[str, SchemaElement] ¶
Auto-generate schema for the current config class and validate config class
Note: there is an assumption here that the class of the value in the default config file is
- config_filename(create_if_nonexistent=False)¶
Filename for saving config items
- property defaults¶
Expose the default values to allow resetting of defaults. No setter should ever be created for this!
- finalise()¶
Call this at the end of the config to make this class ‘final’ and to set up the config file schema
- load()¶
- load_from_file_object(file)¶
Load config file
- override_with_defaults()¶
Set the config entries to defaults, and prevent saving from happening
Added with the ability to disable for testing in mind
- save()¶
- save_to_file_object(file)¶
Save config file
Only changed and unknown variables will be included in the saved file
- validate(key, value)¶
Check whether a value conforms to the type in the schema
- exception sas.system.config.config_meta.ConfigLocked(message)¶
Bases:
Exception
- __doc__ = None¶
- __init__(message)¶
- __module__ = 'sas.system.config.config_meta'¶
- __weakref__¶
list of weak references to the object
sas.system.config.schema_elements module¶
- exception sas.system.config.schema_elements.CoercionError(message)¶
Bases:
Exception
Raised when we can’t make a variable conform to the schema
- __doc__ = " Raised when we can't make a variable conform to the schema"¶
- __init__(message)¶
- __module__ = 'sas.system.config.schema_elements'¶
- __weakref__¶
list of weak references to the object
- class sas.system.config.schema_elements.SchemaBool¶
Bases:
SchemaVariable
- __abstractmethods__ = frozenset({})¶
- __doc__ = None¶
- __module__ = 'sas.system.config.schema_elements'¶
- _abc_impl = <_abc._abc_data object>¶
- coerce(value)¶
Force a variable to conform to the schema, if possible
- schema_variable_type: str = 'bool'¶
- class sas.system.config.schema_elements.SchemaElement¶
Bases:
ABC
Base class for schema elements
- __abstractmethods__ = frozenset({'coerce'})¶
- __dict__ = mappingproxy({'__module__': 'sas.system.config.schema_elements', '__doc__': ' Base class for schema elements', 'coerce': <function SchemaElement.coerce>, 'validate': <function SchemaElement.validate>, '__eq__': <function SchemaElement.__eq__>, '__dict__': <attribute '__dict__' of 'SchemaElement' objects>, '__weakref__': <attribute '__weakref__' of 'SchemaElement' objects>, '__hash__': None, '__abstractmethods__': frozenset({'coerce'}), '_abc_impl': <_abc._abc_data object>, '__annotations__': {}})¶
- __doc__ = ' Base class for schema elements'¶
- __eq__(value)¶
Return self==value.
- __hash__ = None¶
- __module__ = 'sas.system.config.schema_elements'¶
- __weakref__¶
list of weak references to the object
- _abc_impl = <_abc._abc_data object>¶
- abstract coerce(value)¶
Force a variable to conform to the schema, if possible
- exception sas.system.config.schema_elements.SchemaError(message)¶
Bases:
Exception
Raised when there are problems creating a schema
- __doc__ = ' Raised when there are problems creating a schema'¶
- __init__(message)¶
- __module__ = 'sas.system.config.schema_elements'¶
- __weakref__¶
list of weak references to the object
- class sas.system.config.schema_elements.SchemaFloat¶
Bases:
SchemaVariable
- __abstractmethods__ = frozenset({})¶
- __doc__ = None¶
- __module__ = 'sas.system.config.schema_elements'¶
- _abc_impl = <_abc._abc_data object>¶
- coerce(value)¶
Force a variable to conform to the schema, if possible
- schema_variable_type: str = 'float'¶
- class sas.system.config.schema_elements.SchemaInt¶
Bases:
SchemaVariable
- __abstractmethods__ = frozenset({})¶
- __doc__ = None¶
- __module__ = 'sas.system.config.schema_elements'¶
- _abc_impl = <_abc._abc_data object>¶
- coerce(value)¶
Force a variable to conform to the schema, if possible
- schema_variable_type: str = 'int'¶
- class sas.system.config.schema_elements.SchemaList(child_type: SchemaElement)¶
Bases:
SchemaElement
Schema Element representing a homogeneous list
- __abstractmethods__ = frozenset({})¶
- __doc__ = ' Schema Element representing a homogeneous list'¶
- __eq__(other: SchemaElement)¶
Return self==value.
- __hash__ = None¶
- __init__(child_type: SchemaElement)¶
- __module__ = 'sas.system.config.schema_elements'¶
- __repr__()¶
Return repr(self).
- _abc_impl = <_abc._abc_data object>¶
- coerce(value)¶
Force a variable to conform to the schema, if possible
- class sas.system.config.schema_elements.SchemaNonSpecified¶
Bases:
SchemaElement
Representation of a list with elements of an unknown type - we use this when an empty list is in the config, or default is set to None
- __abstractmethods__ = frozenset({})¶
- __doc__ = ' Representation of a list with elements of an unknown type -\n we use this when an empty list is in the config, or default is set to None'¶
- __eq__(other: SchemaElement)¶
Return self==value.
- __hash__ = None¶
- __init__()¶
- __module__ = 'sas.system.config.schema_elements'¶
- __repr__()¶
Return repr(self).
- _abc_impl = <_abc._abc_data object>¶
- coerce(value)¶
Force a variable to conform to the schema, if possible
- class sas.system.config.schema_elements.SchemaStr¶
Bases:
SchemaVariable
- __abstractmethods__ = frozenset({})¶
- __doc__ = None¶
- __module__ = 'sas.system.config.schema_elements'¶
- _abc_impl = <_abc._abc_data object>¶
- coerce(value)¶
Force a variable to conform to the schema, if possible
- schema_variable_type: str = 'str'¶
- class sas.system.config.schema_elements.SchemaVariable¶
Bases:
SchemaElement
SchemaElement for values (i.e. float, int, bool, str)
- __abstractmethods__ = frozenset({'coerce'})¶
- __annotations__ = {'schema_variable_type': <class 'str'>}¶
- __doc__ = ' SchemaElement for values (i.e. float, int, bool, str)'¶
- __eq__(other: SchemaElement)¶
Return self==value.
- __hash__ = None¶
- __init__()¶
- __module__ = 'sas.system.config.schema_elements'¶
- __repr__()¶
Return repr(self).
- _abc_impl = <_abc._abc_data object>¶
- schema_variable_type: str = ''¶
- sas.system.config.schema_elements.create_schema_element(name: str, value, recursion_depth: int = 10) SchemaElement ¶
Get an appropriate schema element for a specified config datum
- sas.system.config.schema_elements.pairwise_schema_union(a: SchemaElement | None, b: SchemaElement | None) SchemaElement | None ¶
Pairwise union of Schema Elements
- sas.system.config.schema_elements.schema_union(elements: List[SchemaElement])¶
Union of an arbitrary number of Schema Elements