Source code for apstools.utils.override_parameters

"""
OverrideParameters
+++++++++++++++++++++++++++++++++++++++

Define parameters that can be overridden from a user configuration file.

EXAMPLE:

Create an ``overrides`` object in a new file ``override_params.py``::

    import apstools.utils
    overrides = apstools.utils.OverrideParameters()

When code supports a parameter for which a user can provide
a local override, the code should import the ``overrides``
object (from the ``override_params`` module),
and then register the parameter name, such as this example::

    from override_params import overrides
    overrides.register("minimum_step")

Then later::

    minstep = overrides.pick("minimum_step", 45e-6)

In the user's configuration file that will override
the value of ``45e-6`` (such as can be loaded via
``%run -i user.py``), import the `overrides``
object (from the ``override_params`` module)::

    from override_params import overrides

and then override the attribute(s) as desired::

    overrides.set("minimum_step", 1.0e-5)

With this override in place, the ``minstep`` value
(from :meth:`~apstools.utils.OverrideParameters.pick()`)
will be ``1e-5``.

Get a pandas DataFrame object with all the overrides::

    overrides.summary()

which returns this table::

        parameter    value
    0  minimum_step  0.00001

----

.. autosummary::

   ~OverrideParameters
"""


import pandas as pd


[docs]class OverrideParameters: """ Define parameters that can be overridden from a user configuration file. NOTE: This is a pure Python object, not using ophyd. .. autosummary:: ~pick ~register ~reset ~reset_all ~set ~summary (new in apstools 1.5.2) """ def __init__(self): # ALWAYS use ``overrides.undefined`` for comparisons and resets. self.undefined = object() self._parameters = {}
[docs] def register(self, parameter_name): """ Register a new parameter name to be supported by user overrides. """ if parameter_name not in self._parameters: self._parameters[parameter_name] = self.undefined
def _check_known(self, parameter_name): if parameter_name not in self._parameters: raise KeyError( f"Unknown parameter {parameter_name}. First call register()." )
[docs] def set(self, parameter_name, value): """ Define an override value for a known parameter. """ self._check_known(parameter_name) self._parameters[parameter_name] = value
[docs] def reset(self, parameter_name): """ Remove an override value for a known parameter. (sets it to undefined) """ self._check_known(parameter_name) self._parameters[parameter_name] = self.undefined
[docs] def reset_all(self): """ Remove override values for all known parameters. (sets all to undefined) """ for parm in self._parameters.keys(): self.reset(parm)
[docs] def pick(self, parameter, default): """ Return either the override parameter value if defined, or the default. """ value = self._parameters.get(parameter, default) if value == self.undefined: value = default return value
[docs] def summary(self): """ Return a pandas DataFrame with all overrides. Parameter names that have no override value will be reported as ``--undefined--``. """ parameters = [] values = [] for parm in sorted(self._parameters.keys()): parameters.append(parm) values.append(self.pick(parm, "--undefined--")) return pd.DataFrame(dict(parameter=parameters, value=values))
# ----------------------------------------------------------------------------- # :author: Pete R. Jemian # :email: jemian@anl.gov # :copyright: (c) 2017-2022, UChicago Argonne, LLC # # Distributed under the terms of the Creative Commons Attribution 4.0 International Public License. # # The full license is in the file LICENSE.txt, distributed with this software. # -----------------------------------------------------------------------------