Package: vivify
VivifyOverviewVivify is a lightweight Python library for INI style object initialisation. Using Vivify, you can instantiate classes and set attributes using values provided from an external configuration. Vivify supports both POD types as well as more complex objects and relationships. This is particularly useful in domains where the configuration is very closely coupled to the objects.InstallationInstalling Vivify is easy! Vivify is available on the Python Packaging Index. If you're using Poetry thenpoetry add vivify, otherwise:pipinstallvivifyUsageThe snippets shown below are provided in full in theexamples directoryand demonstrate using an external configuration to instantiate some pre-defined classes. Further examples are also supplied in the examples directory.This example showcases how Vivify supports complex relationships between classes. In this case, there is a bidirectional associative relationship between classesAandBandBhas an additional variable of typeV.classV(list[int],Vivifiable):@classmethoddefvivify(cls,object):returncls(map(int,object.split(",")))classA(object):b:BclassB(object):a:Av:VNote that in the code above we should specify the types of any instance variables. This is so that Vivify can instantiate the correct type for a specified variable, e.g. to distinguish between a string and a reference to another object in the configuration. It is also important that any attributes specified in the configuration should be settable (or at the very least an attempt to set the attribute should not fail).The following configuration INI file (example.ini) contains the options we want to use to instantiate two instances of these classes namedfooandbar.[main]foo=Abar=B[foo]i=1b=bar[bar]a=foov=1, 2, 3Themainsection where variables are named can be given any valid section name other than that which is reserved for supplying default values for sections - this is defined as"DEFAULT"in the standardconfiguration file parsing library. Note how the other section names correspond to the variable names provided in themainsection.# initialise the config parser and read the ini fileconfig=ConfigParser()withopen("example.ini")asf:config.read_file(f)# specify the valid objects for vivificationvivifier=Vivifier(types=[A,B])vivified=vivifier.vivify(instances="main",config=config)# verify that the vivification occurred as expectedassertisinstance(vivified["foo"],A)assertisinstance(vivified["bar"],B)assertvivified["foo"].b==vivified["bar"]assertvivified["bar"].a==vivified["foo"]assertvivified["bar"].v==[1,2,3]LimitationsMost simple cases should work without issue. Things get complicated and more care should be taken when there are multiple possible types for a value. Consider an attribute with the type annotationUnion[list[int], Optional[str]]. With a configuration value ofNone, there are two possible ways this could be interpreted: (i)None, and (ii)"None"(becausestr(None)returns"None"). Thelist[int]annotation will be skipped because it is a parameterised generic and cannot be instantiated. Currently, the actual type chosen for the is entirely dependent on the ordering of the result of a call toget_argsfrom thetyping extensionslibrary. The first valid matching type is picked for setting the attributes value.fromtypingimportOptional,Unionfromtyping_extensionsimportget_argslogging.basicConfig(level=logging.DEBUG,format="%(asctime)s[%(levelname)s]%(message)s",handlers=[logging.StreamHandler(sys.stdout)],)assert(str(get_args(Union[list[int],Optional[str]]))=="(list[int], <class 'str'>, <class 'NoneType'>)")In this case, the value would be set to the string"None"because this matches first (after the invalidlist[int]) and the permissivestrtype coercion accepts None as an argument.If you are especially concerned about which type is used then it is a good idea to either make the typing more strict or useVivifiableobjects (preferred approaches) or alternatively check a call toget_argsyourself on the type to verify that the implementation will work as you expect. Vivify provides extensive logging so you can see how variables are handled internally.LicenceCopyright © 2022Adam D WalkerLicensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.