Package: b3j0f.conf
DescriptionPython object configuration library in reflective and distributed concerns.LinksHomepagePyPIDocumentationInstallationpip install b3j0f.confFeaturesThis library provides a set of object configuration tools in order to ease development of systems based on configuration resources such as files, DB documents, etc. in a reflexive, functional and distributed context.Configuration processing is done is in 5 steps with only two mandatories:optional : configuration model specification. You define which parameters you want to setup (default value, type, etc.).optional : configuration driver selection. You define the nature of configuration resources (xml, json, ini, etc.).mandatory : configuration resource edition. You define your configuration resources (files, DB documents, etc.).optional : bind a configurable to python object(s). You bind a configurable to objects to setup for a reflexive use.mandatory : apply configuration to a python object. You setup your python objects.In order to improve reflexive concerns, this library has been developed with very strong flexible features available at runtime.It is possible to custom every parts directly at runtime with high speed execution concerns.You can customize:parsing functions.drivers.configuration process.configuration meta-model.ConfigurationThe package b3j0f.conf.model provides Configuration class in order to inject configuration resources in a configurable class.Configuration resources respect two levels of configuration same as the ini configuration model. Both levels are respectively:Category: permits to define a set of parameters unique by name.Parameter: couple of property name and value.And all categories/parameters are embedded in a Configuration class.Configuration and Categories are ordered dictionaries where key values are inner element names. Therefore, Parameter names are unique per Categories, and Category/Parameter names are unique per Configuration.Parameter OverridingIn a dynamic and flexible way, one Configurable class can be bound to several Categories and Parameters. The choice is predetermined by the class itself. That means that one Configurable class can use several configuration resources and all/some/none Categories/Parameters in those resources. In such a way, the order is important because it permits to keep only last parameter values when parameters have the same name.This overriding is respected by default with Configurable class inheritance. That means a sub class which adds a resource after its parent class resources indicates than all parameters in the final resources will override parameters in the parent class resources where names are the sames.Name such as a regular expressionEven if a parameter uses a name, it is possible to use this name such as a regular expression name.In this case, while reading a configuration from a resource, all configuration parameters which match the regular expression will use the same attributes as defined in the parameter with the regular expression. And a name which is the name from the configuration resource.ParserThe package b3j0f.conf.parser provides parsers used to deserialize parameter values.All parsers use special entries such as:%(lang:)expr%: string value of a programming language expression.langis the target language (default is python) andexpris the expression to evaluate. For example,%"testy"[:-1]%equalstest.@((rpath/)cname.)[history]pname: reference to another parameter value (thanks to the idea from the pypiconfigproject) where:rpath: optional resource path.cname: optional category name.history: optional parameter history in the arborescence from the (current) category. If not given, last parameter value is given.pname: parameter name.For example:@testdesignates the final value of the parametertest.@myconf.json/testis the parametertestfrom the resourcemyconf.json.@mycat...testis the parametertestdefined two categories before the categorymycat.If the parameter configuration value is of the format=(lang:)expr, the result is an evaluation ofexprin the given languagelang. For example,=2equals the integer 2.=sys.maxsizeis the maxsize value from the sys module (thanks to the best effort property).Finally, here are reserved keywords in an evaluated expression:conf: current configuration.configurable: current configurable.NoteBy default,besteffortandsafeproperties are enabled. They respectively permit to resolve absolute object path and avoid to call I/O functions. They can be changed in the resperive Configurable, like the expression execution scope value which contains by default both configuration andconfigurablenoted above.ConfigurableA Configurable class is provided in the b3j0f.conf.configurable.core module. It permits to get parameters from configuration resources and setup them to a python object or in a method/function parameters.It inherits from theb3j0f.annotation.Annotationclass (annotation). That means it can be used such as an annotation (decorator with annotation functions). For example, bound Configurables to an objectoare retrieved like this:Configurable.get_annotations(o).In order to perform a configuration setup, it uses:conf: configuration model.drivers: configuration resource drivers.scope: parsing execution scope.besteffort: boolean flag which aims to resolve automatically absolute object path. True by default.safe: boolean flag which aims to cancel calls to I/O functions. True by default.logger: logger which will handle all warning/error messages. None by default.Annotated elements are bound and can all be (re)configured once in using the method applyconfiguration.DriverDrivers are the mean to parse configuration resources, such as files, DB documents, etc. from a configuration model provided by a Configurable object.By default, conf drivers are able to parse json/ini/xml files. Those last use a relative path given by the environment variableB3J0F_CONF_DIRor from directories (in this order)/etc,/usr/local/etc,~/etc,~/.config,~/config, current execution directory or absolute path.ExampleBind configuration files to an objectBind the configuration file~/etc/myobject.confand~/.config/myobject.confto a business classMyObject(the relative path~/etccan be changed thanks to the environment variableB3J0F_CONF_DIR).The configuration file contains a category namedMYOBJECTcontaining the parameters:myattrequals'myvalue'.sixequals6.twelveequalssix * 2.0.Let the following configuration file~/etc/myobject.confin ini format:[MYOBJECT]myattr=myvaluetwelve==@six * 2.0Let the following configuration file~/.config/myobject.confin json format:{"MYOBJECT":{"six":6}}The following code permits to load upper configuration to a python object.fromb3j0f.confimportConfigurable# instantiate a business class@Configurable(paths='myobject.conf')classMyObject(object):passmyobject=MyObject()# assert attributesassertmyobject.myattr=='myvalue'assertmyobject.six==6assertisinstance(myobject.six,int)assertmyobject.twelve==12assertisinstance(myobject.twelve,float)The following code permits to load upper configuration to a python function.fromb3j0f.confimportParameter,Array# instantiate a business class and ensure twelve is converted into an integer and a string with commas is converted into an array of integers.@Configurable(paths='myobject.conf',conf=[Parameter('default',value=len('default')),# default value for the parameter defaultParameter('twelve',ptype=int),Parameter('integers',svalue='1,2,3',ptype=Array(int)))defmyfunc(myattr=None,six=None,twelve=None,default=None):# Only None values will be setted by the configurationreturnmyattr,six,twelve,defaultmyattr,six,twelve,default=myfunc(twelve=46)# assert attributesassertmyobject.default==7assertmyobject.myattr=='myvalue'assertmyobject.six==6assertmyobject.twelve==46assertisinstance(myobject.twelve,int)assertmyobject.integers==[1,2,3]Class configurationfromb3j0f.confimportcategoryfromb3j0f.confimportConfigurable# class configuration@Configurable(conf=category('land',Parameter('country',value='fr')))classWorld(object):passworld=World()assertworld.country=='fr'One configuration with several objectsland=Configurable.get_annotations(world)[0]# class method for retrieving Configurables@land# bind land to World2classWorld2(object):passworld2=World2()assertWorld2().country=='fr'classWorld3(object):passworld3=World3()land.applyconfiguration([world3])# apply land on world3 without annotated itassertworld3.country=='fr'world3s=(land(World3())for_inrange(5))# annotate a set of worldsland.conf['land']['country']='en'# change default country codeland.applyconfiguration()# update all annotated objectsfor_world3inworld3s:assert_world3.country=='en'assertworld2.country=='en'assertworld3.country=='fr'# check not annotated element has not changedConfigure object constructorland.autoconf=False# disable autoconf@landclassWorld4(object):def__init__(self,country=None):self.safecountry=countryworld4=World4()assertnothasattr(world4,'country')# disabled auto conf side effectassertworld4.safecountry='en'land.applyconfiguration()# configure all land targetsassertworld4.country=='en'Configure function parameters@landdefgetcountry(country=None):print(country)returncountryassertgetcountry()=='en'land['land']['country']='fr'assertgetcountry()=='fr'Configure embedded objectsfromb3j0f.confimportconfiguration,category,ParameterclassSubTest(object):pass@Configurable(conf=(configuration(category('',Parameter('subtest',value=SubTest)),# the prefix ':' refers (recursively) to a sub configuration for the parameter named with the suffix after ':'category(':subtest',Parameter('subsubtest',value=SubTest)),category(':subtset:subsubtest',Parameter('test',value=True)))))classTest(object):passtest=Test()assertisinstance(test.subtest,SubTest)assertisinstance(test.subtest.subsubtest)assertnothasattr(test.subtest,'test')asserttest.subtest.subsubtest.testisTrue# and you can still apply configurationConfigurable.get_annotations(test)[0].conf[':subtset:subsubtest']['test']=Falseapplyconfiguration(targets=[test])asserttest.subtest.subsubtest.testisFalseConfigure metaclassesfromsiximportadd_metaclass@Configurable(conf=Parameter('test',value=True))classMetaTest(type):pass@add_metaclass(MetaTest)classTest(object):passtest=Test()asserttest.testisTruePerspectiveswait feedbacks during 6 months before passing it to a stable version.Cython implementation.add GUI in order to ease management of multi resources and categorized parameters.Donation