mypythontools.config module — mypythontools 24-08-2021 documentation

# mypythontools.config module

This is not module that configure library mypythontools, but module that help create config for your project.

## What

1. Simple and short syntax.

2. Ability to have docstrings on variables (not dynamically, so visible in IDE) and good for sphinx docs.

3. Type checking, one-of-options checking.

4. Also function evaluation from other config values (not only static value stored).

5. Options hierarchy (nested options).

## How

Boosted property with simplified implementation. To be able to provide docstrings in IDE, first function is created.

## Examples:

    >>> class SimpleConfig(ConfigBase):
    ...     @MyProperty(int)  # Use tuple like (str, int, bool) if more classes.
    ...     def var() -> int:  # This is for type hints in IDE.
    ...         '''
    ...         Type:
    ...             int
    ...
    ...         Default:
    ...             123
    ...
    ...         This is docstrings (also visible in IDE, because not defined dynamically).'''
    ...
    ...         return 123  # This is initial value that can be edited.
    ...
    ...     @MyProperty()  # Even if you don't need any params, use empty brackets
    ...     def evaluated(self) -> int:
    ...         return self.var + 1
    ...
    >>> config = SimpleConfig()
    >>> config.var
    123
    >>> config.var = 665
    >>> config.var
    665
    >>> config['var']  # You can also access params as in a dictionary
    665
    >>> config.evaluated
    666
    >>> config.var = "String is problem"
    Traceback (most recent call last):
    TypeError: ...

This is how help looks like in VS Code

You can also use options checker validation.

    >>> class SimpleConfig(ConfigBase):
    ...     @MyProperty(options=[1, 2, 3])
    ...     def var(self) -> int:
    ...         2  # This means that value will not be set on init
    ...
    >>> config = SimpleConfig()
    >>> config.var = 4
    Traceback (most recent call last):
    KeyError: ...

You can also edit getter or setter. You can use lambda function (if more logic, it’s better to use normal property and add type checking manually).

Use setattr and name with underscore as prefix or self.private_name self means property, not config object.

    >>> class SimpleConfig(ConfigBase):
    ...     @MyProperty(
    ...         int,
    ...         fset=lambda self, object, new: (
    ...             print("I'm listener, i can call any function on change."),
    ...             setattr(object, self.private_name, new + 1),
    ...         ),
    ...     )
    ...     def with_setter() -> int:
    ...         return 1
    ...
    >>> config = SimpleConfig()
    >>> config.with_setter
    1
    >>> config.with_setter = 665
    I'm listener, i can call any function on change.
    >>> config.with_setter
    666

### Hierarchical config

If last level, do inherit from ConfigBase, else inherit from ConfigStructured

Note

Use unique values for all config variables even if they are in various subconfig.

    >>> class Config(ConfigStructured):
    ...     def __init__(self) -> None:
    ...         self.subconfig1 = self.SubConfiguration1()
    ...         self.subconfig2 = self.SubConfiguration2()
    ...
    ...     class SubConfiguration1(ConfigStructured):
    ...         def __init__(self) -> None:
    ...             self.subsubconfig = self.SubSubConfiguration()
    ...
    ...         class SubSubConfiguration(ConfigBase):
    ...             @MyProperty(options=[0, 1, 2, 3])
    ...             def value1() -> int:
    ...                 '''Documentation here
    ...
    ...                 Options: [0, 1, 2, 3]
    ...                 '''
    ...                 return 3
    ...
    ...             @MyProperty()
    ...             def value2(self):
    ...                 return self.value1 + 1
    ...
    ...     class SubConfiguration2(ConfigBase):
    ...         @MyProperty()
    ...         def other_val(self):
    ...             return self.value2 + 1
    ...
    ...     # Also subconfig category can contain values itself
    ...     @MyProperty(options=[0, 1, 2, 3])
    ...     def value3() -> int:
    ...         return 3
    ...
    >>> config = Config()
    ...
    >>> config.subconfig1.subsubconfig.value2
    4

You can access value from config as well as from subcategory

    >>> config.value2
    4

### Copy

Sometimes you need more instances of settings and you need copy of existing configuration. Copy is deepcopy by default.

    >>> config2 = config.copy()
    >>> config2.value3 = 0
    >>> config2.value3
    0
    >>> config.value3
    3

### Bulk update

Sometimes you want to update many values with flat dictionary.

    >>> config.update({'value3': 2, 'value1': 0})
    >>> config.value3
    2

### Get flat dictionary

There is a function that will export all the values to the flat dictionary (no dynamic anymore, just values).

    >>> config.get_dict()
    {'value3': 2, 'value1': 0, 'value2': 1, 'other_val': 2}

### Reset

You can reset to default values

    >>> config.value1 = 1
    >>> config.reset()
    >>> config.value1
    3

## Sphinx docs

If you want to have documentation via sphinx, you can add this to conf.py:

    napoleon_custom_sections = [
        ("Types", "returns_style"),
        ("Type", "returns_style"),
        ("Options", "returns_style"),
        ("Default", "returns_style"),
        ("Example", "returns_style"),
        ("Examples", "returns_style"),
    ]

Here is example

class mypythontools.config.ConfigBase(*args, **kwargs)

  Bases: `object`

  Main config class. If need nested config, use ConfigStructured instead. You can find working examples in module docstrings.

  copy()
  frozen = False
  get_dict()
  reset()
  update(dict)

class mypythontools.config.ConfigMeta(name, bases, dct)

  Bases: `type`

  Metaclass that will edit Config class. Main reason is for being able to define own __init__ but still has functionality from parent __init__ that is necessary. With this meta, there is no need to use super().__init__ by user.

  As user, you probably will not need it. It’s used internaly if inheriting from ConfigStructured.

class mypythontools.config.ConfigStructured(dict_values=None, frozen=None)

  Bases: `mypythontools.config.ConfigBase`

  Class for creating config. Read why and how in config module docstrings.

  get_dict()