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:

  1. They have a tendency to accumulate junk because people dont realise that a config item is no longer needed

  2. It’s hard to trace the usages and types because values are loaded at runtime

  3. 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:

  1. Program settings that are configurable by users through the GUI

  2. Program settings that have no GUI editor, but that some advanced users might want to set manually with a text editor

  3. Settings that control developer tools, e.g. debug modes

  4. Very little else

Things that don’t belong, but were previously in the config:

  1. 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

  2. Paths to resources within sasview (use importlib.resources instead)

  3. Blocks of data that won’t be modified by the user and used primarily by single class - e.g. the text for a message

  4. 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

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

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

update(data: dict[str, Any])

Set the fields of the config from a dictionary

validate(key, value)

Check whether a value conforms to the type in the schema

exception sas.system.config.config_meta.ConfigLocked(message)

Bases: Exception

class sas.system.config.config_meta.ConfigMeta(name, bases, classdict)

Bases: type

exception sas.system.config.config_meta.MalformedFile(message)

Bases: Exception

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

class sas.system.config.schema_elements.SchemaBool

Bases: SchemaVariable

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

abstractmethod coerce(value)

Force a variable to conform to the schema, if possible

validate(value: Any) bool

Return true if value is valid according to the schema

exception sas.system.config.schema_elements.SchemaError(message)

Bases: Exception

Raised when there are problems creating a schema

class sas.system.config.schema_elements.SchemaFloat

Bases: SchemaVariable

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

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

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

coerce(value)

Force a variable to conform to the schema, if possible

class sas.system.config.schema_elements.SchemaStr

Bases: SchemaVariable

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)

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

Module contents