API

more-kivy-app

Base class for kivy apps that is crash resistant with builtin configuration.

App

The base App class.

class more_kivy_app.app.MoreKivyApp(yaml_config_path=None, **kw)

Bases: App

The base app.

app_settings = {}

A dict that contains the tree-config settings for the app for all the configurable classes. See that module for details.

The keys in the dict are configuration names for a class and its values are property values or nested dicts whose keys are class attributes names and values are their values. These attributes are the ones listed in _config_props_. See tree-config for how configuration works.

apply_app_settings()

Applies the app config stored in app_settings to the application instance. See tree_config.apply_config().

ask_cannot_close(*largs, **kwargs)

Called by kivy when the user tries to close the app. It only closes if this returns False.

This is only used when the app is started with run_app() or run_app_async().

build(root=None)

Similar to App’s build, but it takes the root widget if provided and if inspect is True, it activates kivy’s inspector.

Parameters:

root – The root widget instance.

Returns:

The root widget

clean_up()

Called by run_app() or run_app_async() after the app closes to clean up any remaining resources.

By default, if inspect is enabled, it cleans up after it.

property data_path

The install dependent path to the persistent config data directory. It is automatically added to the kivy resource PATH.

if this is running under a PyInstaller installation, it is the path that contains the executable, it’s the data folder next to the app class’s python file.

dump_app_settings_to_file()

Saves the app config from the app to the config file at yaml_config_path. See tree_config.dump_config().

ensure_file(filename)

Returns the full path to filename by searching for it in kivy’s resource directories if it exists. Otherwise, it create the empty file and returns the path to it.

get_logger()

Returns the logger to use in handle_exception() to log messages.

Defaults to returning the Kivy Logger.

handle_exception(msg, exc_info=None, level='error', *largs)

Should be called whenever an exception is caught in the app.

If the app is started with run_app() or run_app_async(), this is called if kivy encounters an error. Similarly, app_error(), app_error_async(), and report_exception_in_app() call this on the app upon an exception.

It logs the message to the logger using get_logger().

Parameters:
exception: string or exception object

The caught exception (i.e. the e in except Exception as e)

exc_info: stack trace

If not None, the return value of sys.exc_info() or a stringified version of it. It is used to log the stack trace.

level: string

The log level to use on the message. Can be 'error', 'exception' (with the same meaning), or any other python log level.

init_load()

Creates any config files and adds data_path to the kivy resource PATH when the app is instantiated.

inspect = False

Enables GUI inspection. If True, it is activated by hitting ctrl-e in the GUI.

load_app_settings_from_file()

Reads the config from the yaml_config_path file and saves it to app_settings. See tree_config.read_config_from_file().

yaml_config_path = None

The full path to the config file used for the app.

If it’s None when __init__ of the base class is called, it is set to ClassName_config.yaml, where ClassName is the name of the App class.

more_kivy_app.app.app_error(app_error_func=None, threaded=True)

A decorator which wraps the function in try…except and calls MoreKivyApp.handle_exception() when a exception is raised.

E.g.:

@app_error
def do_something():
    do_something
more_kivy_app.app.app_error_async(app_error_func=None, threaded=True)

A decorator which wraps the async function in try…except and calls MoreKivyApp.handle_exception() when a exception is raised.

E.g.:

@app_error
async def do_something():
    do_something
more_kivy_app.app.report_exception_in_app(e, exc_info=None, threaded=True)

Takes the error and reports it to MoreKivyApp.handle_exception().

Parameters:
  • e – The error

  • exc_info – If not None, the return value of sys.exc_info() or a stringified version of it.

  • threaded – If the app should be called in a thread safe manner, e.g. if called from another thread.

more_kivy_app.app.run_app(cls_or_app)

Entrance method used to start the App. It runs, or instantiates and runs a MoreKivyApp type instance.

async more_kivy_app.app.run_app_async(cls_or_app, async_lib=None)

Entrance method used to start the App. It runs, or instantiates and runs a MoreKivyApp type instance.

Configuration

Exports kivy-aware version of the configuration functions.

class more_kivy_app.config.Configurable

Bases: object

tree_config uses a duck typing approach. E.g. when applying config, apply_config() will call apply_config_property if it is defined for the objects being configured, otherwise it directly sets the properties.

The Configurable can be used as a base-class instead of the duck typing approach and it defines all the special config methods. It can also be used as a guide to the names of the special config hooks available when using the duck typing approach.

There are only two possible benefits to using Configurable. (1) it defines _config_props / _config_children which caches the names of the configurable properties / children on a per-class basis. Unlike the duck typing approach that gathers them afresh every time. (2) You can use super for properties you want to use the default handling approach as in the following example.

However, the main reason for the class’ existance is to define the configuration API in one place so we can refer to the method names.

Consider a duck typing example and the inheritance based example:

class DuckApp:

    _config_props_ = ('frame', 'color')

    frame = 'square'
    color = 'blue'

class ConfigurableApp(Configurable):

    _config_props_ = ('frame', 'color')

    frame = 'square'
    color = 'blue'

Both behave identically with respect to configuration:

>>> read_config_from_object(DuckApp())
{'frame': 'square', 'color': 'blue'}
>>> read_config_from_object(ConfigurableApp())
{'frame': 'square', 'color': 'blue'}

However, if we wanted to customize setting the frame property, using Configurable will be slighlty simpler since you can call super to set the remaining properties in the default way. E.g.:

class DuckApp:

    _config_props_ = ('frame', 'color')

    frame = 'square'

    color = 'blue'

    def apply_config_property(self, name, value):
        if name == 'frame':
            self.frame = value * 2
        else:
            setattr(self, name, value)

class ConfigurableApp(Configurable):

    _config_props_ = ('frame', 'color')

    frame = 'square'

    color = 'blue'

    def apply_config_property(self, name, value):
        if name == 'frame':
            self.frame = value * 2
        else:
            super().apply_config_property(name, value)
property _config_children: Dict[str, str]

A property, which if defined will be used to get all the configurable children instead of using _config_children_. It returns the dict of configurable children like _config_children_.

_config_children_: Dict[str, str] = {}

A dict of configurable children objects of the class that is used by the configuration API to traverse the configuration “tree” and to configure all these objects.

The keys are the human friendly names of the children and the values are the corresponding property names storing the child.

Each sub/super-class can define this and the children are accumulated across all the sub/super-classes.

property _config_props: List[str]

A property, which if defined will be used to get all the configurable properties instead of using _config_props_. It returns the list of configurable properties like _config_props_.

_config_props_: Tuple[str] = ()

A list of configurable property names of the class that is set/read by the configuration API.

Each sub/super-class can define this and the properties are accumulated across all the sub/super-classes.

apply_config_child(name: str, prop: str, obj: Any, config: Dict[str, Any] | List[Dict[str, Any]]) Any

If defined, it is called to apply the configuration for all the properties of the child, for each child.

When defined, it must either call apply_config() which also implicitly dispatches post_config_applied(). If you manually configure the child, you also have to call post_config_applied() manually.

Parameters:
  • name – The human friendly name of the child that will be configured. It is the same as the keys in _config_children_.

  • prop – The property name storing the child that will be configured. It is the same as the values in _config_children_.

  • obj – The configurable child object or a list of objects if the property is a list.

  • config – The config dict or list of config dicts to be applied to the child(ern).

apply_config_property(name: str, value: Any) None

If defined, it is called to set the value of a configurable property of the class.

Parameters:
  • name – The name of the property.

  • value – The value of the property.

get_config_property(name: str) Any

If defined, it is called by the configuration system to get the value of the named property.

Parameters:

name – The name of the property to get.

post_config_applied() None

If defined, it is called by the configuration system when it finishes applying all the configuration properties/children of this object.

more_kivy_app.config.apply_config(obj, config: ~typing.Dict[str, ~typing.Any], get_attr=<built-in function getattr>, set_attr=<built-in function setattr>) None

Takes the config data read with e.g. read_config_from_object() or read_config_from_file() and applies them to the object and its children.

Calls post_config_applied on the object and/or its children after they are configured if all/any have such a method.

Parameters:
  • obj – The object to which to apply the config.

  • config – The config dict.

  • get_attr – The function to use to get the child value from the object and its children. defaults to getattr.

  • set_attr – The function to use to set the property values for the object and its children. defaults to setattr.

The object’s config is applied before its children’s config is applied.

E.x.:

class App:

    _config_props_ = ('name', )

    _config_children_ = {'the box': 'box'}

    name = 'chair'

    box = None

class Box:

    _config_props_ = ('volume', )

    volume = 12

    def apply_config_property(self, name, value):
        print('applying child', name)
        setattr(self, name, value)

    def post_config_applied(self):
        print('done applying child')

then:

>>> app = App()
>>> app.box = Box()
>>> d = read_config_from_object(app)
>>> d
{'the box': {'volume': 12}, 'name': 'chair'}
>>> d['name'] = 'bed'
>>> d['the box']['volume'] = 34
>>> apply_config(app, d)
applying child volume
done applying child
>>> app.name
'bed'
>>> app.box.volume
34
more_kivy_app.config.create_doc_listener(sphinx_app, package_name, filename, *, yaml_dump_str=functools.partial(<function yaml_dumps>, get_yaml_obj=<function get_yaml>))

Creates a listener for the __config_props__ attributes and dumps the docs of any props listed, to filename. If the file already exists, it extends it with new data and overwrites any exiting properties that we see again in this run.

To use, in the sphinx conf.py file do something like:

def setup(app):
    import package
    create_doc_listener(app, package, 'config_attrs.yaml')

where package is the package for which the docs are generated.

See the guide for a full example.

more_kivy_app.config.dump_config(filename: str | ~pathlib.Path, data: ~typing.Dict[str, ~typing.Any], *, yaml_dump_str=functools.partial(<function yaml_dumps>, get_yaml_obj=<function get_yaml>)) None

Dumps config data gotten with e.g. read_config_from_object() to a yaml file.

Parameters:
  • filename – The yaml filename.

  • data – The config data.

  • yaml_dump_str – The function to encode the config to yaml. Defaults to yaml_dumps().

E.g.:

>>> class App:
>>>     _config_props_ = ('name', )
>>>     name = 'chair'
>>> app = App()
>>> d = read_config_from_object(app)
>>> dump_config('config.yaml', d)
>>> with open('config.yaml') as fh:
...     print(fh.read())

Which prints name: chair.

more_kivy_app.config.load_apply_save_config(obj, filename: str | ~pathlib.Path, get_attr=<built-in function getattr>, set_attr=<built-in function setattr>, *, yaml_dump_str=functools.partial(<function yaml_dumps>, get_yaml_obj=<function get_yaml>), yaml_load_str=<function yaml_loads>) Dict[str, Any]

Applies the config to the object from the yaml file (if the file doesn’t exist it creates it), and then dumps to the yaml file the current config from the object. It also returns the final config dict.

This can be used to set the object from the config, but also making sure the file contains the current config including any new properties not previously there or properties that changed during config application.

Parameters:
  • obj – The configurable object.

  • filename – The yaml filename.

  • get_attr – The function to use to get the property/children values from the object. defaults to getattr.

  • set_attr – The function to use to set the property values of the object and its children. defaults to setattr.

  • yaml_dump_str – The function to encode the config to yaml. Defaults to yaml_dumps().

  • yaml_load_str – The function to parse the yaml string read from the file. Defaults to yaml_loads().

E.x.:

class App:

    _config_props_ = ('name', )

    name = 'chair'

class AppV2:

    _config_props_ = ('name', 'side')

    name = 'chair'

    side = 'left'

then:

>>> app = App()
>>> app.name = 'tree'
>>> load_apply_save_config(app, 'config_app.yaml')
{'name': 'tree'}
>>> app.name
'tree'
>>> # then later for v2 of the app
>>> app_v2 = AppV2()
>>> app_v2.name
'chair'
>>> load_apply_save_config(app_v2, 'config_app.yaml')
{'name': 'tree', 'side': 'left'}
>>> app_v2.name
'tree'
>>> with open('config_app.yaml') as fh:
...     print(fh.read())

this prints:

name: tree
side: left
more_kivy_app.config.load_config(obj, filename: str | ~pathlib.Path, get_attr=<built-in function getattr>, *, yaml_dump_str=functools.partial(<function yaml_dumps>, get_yaml_obj=<function get_yaml>), yaml_load_str=<function yaml_loads>) Dict[str, Any]

Loads and decodes the config from a yaml file. If the config file doesn’t exist, it first dumps the config to the file using read_config_from_object() and dump_config() before loading it.

Parameters:
  • obj – The object from which to dump the config when the files doesn’t exist.

  • filename – The yaml filename.

  • get_attr – The function to use to get the property/children values from the object. defaults to getattr.

  • yaml_dump_str – The function to encode the config to yaml. Defaults to yaml_dumps().

  • yaml_load_str – The function to parse the yaml string read from the file. Defaults to yaml_loads().

E.g.:

>>> class App:
>>>     _config_props_ = ('name', )
>>>     name = 'chair'
>>> load_config(App(), 'app_config.yaml')
{'name': 'chair'}
more_kivy_app.config.read_config_from_file(filename: str | ~pathlib.Path, yaml_load_str=<function yaml_loads>) Dict[str, Any]

Reads and returns the yaml config data dict from a file that was previously dumped with dump_config().

Parameters:
  • filename – The yaml filename.

  • yaml_load_str – The function to parse the yaml string read from the file. Defaults to yaml_loads().

E.g.:

>>> class App:
>>>     _config_props_ = ('name', )
>>>     name = 'chair'
>>> app = App()
>>> d = read_config_from_object(app)
>>> dump_config('config.yaml', d)
>>> read_config_from_file('config.yaml')
{'name': 'chair'}
more_kivy_app.config.read_config_from_object(obj, get_attr=<built-in function getattr>) Dict[str, Any]

Returns a recursive dict containing all the configuration options of the obj and its configurable children.

Parameters:
  • obj – The object from which to get the config.

  • get_attr – The function to use to get the child value from the object and its children. defaults to getattr.

E.x.:

class App:

    _config_props_ = ('name', )

    _config_children_ = {'the box': 'box'}

    name = 'chair'

    box = None

class Box:

    _config_props_ = ('volume', )

    volume = 12

then:

>>> app = App()
>>> app.box = Box()
>>> read_config_from_object(app)
{'the box': {'volume': 12}, 'name': 'chair'}
more_kivy_app.config.write_config_props_rst(obj, project, app, exception, filename, rst_filename, get_attr=<built-in function getattr>, *, yaml_dump_str=functools.partial(<function yaml_dumps>, get_yaml_obj=<function get_yaml>))

Walks through all the configurable classes of obj, recursively by looking at _config_props_ and _config_children_ and using the type hints of these children properties if they are None (e.g. if obj is a class). For each property it loads their docs from the yaml file filename and it generates a rst output file at rst_filename with all the tokens.

For example in the sphinx conf.py file do:

def setup(app):
    app.connect('build-finished', partial(write_config_props_rst, ProjectApp, project_name, filename='config_prop_docs.yaml', rst_filename='source/config.rst'))

where project_name is the name of project and ProjectApp is the App of the package the contains all the configurable objects.

See the guide for a complete example.

Utilities

more_kivy_app.utils.yaml_dumps(value: ~typing.Any, *, get_yaml_obj: ~typing.Callable[[], ~ruamel.yaml.main.YAML] = <function get_yaml>) str

Converts the object to yaml.

Parameters:
  • value – the object to convert.

  • get_yaml_obj – A function such as get_yaml() that will be called to get a yaml object. Defaults to get_yaml().

Returns:

a string yaml representation.