Package: mara-config
mara-configApp composing and configuration infrastructure of the mara ecosystem. The packages functionality contains:a way to compose an mara appa simply config system based on replaceable functionsBuild an appThe goal of mara ecosystem is that if you update a package, new
functionality is added automatically to your app or database
migration automatically include newly declared models. To make
the app still composable, you build a functioncompose_app()in
moduleapp.app. This function should then callmara_config.register_functionality(module)for all modules it wants
to include.Your own app should both contribute functionality (see next section) and
register itself viamara_config.register_functionality(your_module).The default module can be overwritten by setting the env variable:MARA_APP=module.submodule.Contribute functionality in a packageA package has to expose their functionality viaMARA_*iterables
(either lists or functions returning a list or generators). The
iterable contains the to be added functionality. It is advised to
use functions returning a list or generators so functionality will be
lazily loaded when the functionality is actually used. This is
especially important if you use optional dependencies (e.g. a flask
view which exposes the config system, but the config system itself
is usable without the flask views).If a package contains sub-functionality which can be consumed
independently from each other, consider putting them into subpackages
and let the main module return a union of all sub-functionality.Consume contributed functionalityContributed functionally can be consumed by callingmara_config.get_contributed_functionality('MARA_VARIABLE_NAME')which yields
the functionality in tuples(module, content).moduleis the
module used in themara_config.register_functionality(module)call.The consumer should then add the functionality in the right places, e.g.
themarashell command (in the mara-cli package) adds all contributed
click commands as subcommands.Mara configConfiguration system based on replaceable functions.One side declares a replaceable function as config by decorating that
functions with@declare_config(). To change this config,
decorate a replacement function with@set_config('name').The default name of a config isorig_package.funcbut can be overwritten
in the@declare_config('name')decorator.Example# in package which declares APIfrommara_configimportdeclare_config@declare_config("name")defsomething(argument:str=None)->str:return"x"print(something())print(something("ABC"))# In downstream package which want's to overwrite the APIfrommara_configimportset_config@set_config('name')defreplacement_for_something(argument:str=None)->str:returnargumentor'y'print(something())print(something("ABC"))Configs from local_setup.pyPer default alocal_setup.pyin the module defined in the environment
variableMARA_APPand all modules higher up (first one found wins) is
imported. Use this to place all you local modifications to configs and
exclude this file from the repo (.gitignore).Configs from EnvironmentTo aid dockerization, replacement functions are also generated from
environment variables. Environment config is loaded last and wins overlocal_setup.py!This only works for config items which return either numbers (floats),
booleans, or strings.Any environment variable (case insensitive) which starts with 'MARA_' is
turned into functions which returns the value. The rest of the environment
variable name has any__replaced by '.'. If the value is a valid float,
it's returned as a float. If it's a valid bool, it's returned as a boolean.
Otherwise it's returned as a string.E.g. the following variableMARA_PACKAGENAME__CONFIG_ITEM=yis equivalent to the following@set_configcallfrommara_configimportset_config@set_config('packagename.config_item')defreplacement():return'y'Contributed MARA_* functionality in this packagea Flask view to show the current configuration (MARA_FLASK_BLUEPRINTS)an ACL ressource to protect access to the config view (MARA_ACL_RESOURCES)a navigation entry (MARA_NAVIGATION_ENTRY_FNS)Some default configuration entries (MARA_CONFIG_MODULES)To use, add this funcitonality, addmara_config.register_functionality(mara_config)to yourcompose_mara_app()function.Consumed MARA_* functionalityThe packge will load all modules which are declared inMARA_CONFIG_MODULESif asked to show the
current configuration.MARA_CONFIG_MODULESmust be alist/generator/function which returns a listwhich
contains all modules which declare user facing configuration (@declare_config()).
When displaying the config (e.g. viamara print_configor the included flask view),
all modules will be loaded and all included@declare_config()decorated functions
therefore added to the config system.Only user facing configs should be in such modules, interal API can be elsewhere
(but won't be shown if not set).