Skip to main content

A Python library for using INI files to instantiate classes.

Project description

Vivify

Code style: black Keep a Changelog v1.1.0 badge Contributor Covenant Conventional Commits License img

Overview

Vivify 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.

Installation

Installing Vivify is easy! Vivify is available on the Python Packaging Index. If you're using Poetry then poetry add vivify, otherwise:

pip install vivify

Usage

The snippets shown below are provided in full in the examples directory and 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 classes A and B and B has an additional variable of type V.

class V(list[int], Vivifiable):
    @classmethod
    def vivify(cls, object):
        return cls(map(int, object.split(",")))


class A(object):
    b: B


class B(object):
    a: A
    v: V

Note 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 named foo and bar.

[main]
foo = A
bar = B

[foo]
i = 1
b = bar

[bar]
a = foo
v = 1, 2, 3

The main section 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 standard configuration file parsing library. Note how the other section names correspond to the variable names provided in the main section.

# initialise the config parser and read the ini file
config = ConfigParser()
with open("example.ini") as f:
    config.read_file(f)

# specify the valid objects for vivification
vivifier = Vivifier(types=[A, B])
vivified = vivifier.vivify(instances="main", config=config)
# verify that the vivification occurred as expected
assert isinstance(vivified["foo"], A)
assert isinstance(vivified["bar"], B)
assert vivified["foo"].b == vivified["bar"]
assert vivified["bar"].a == vivified["foo"]
assert vivified["bar"].v == [1, 2, 3]

Limitations

Most 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 annotation Union[list[int], Optional[str]]. With a configuration value of None, there are two possible ways this could be interpreted: (i) None, and (ii) "None" (because str(None) returns "None"). The list[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 to get_args from the typing extensions library. The first valid matching type is picked for setting the attributes value.

from typing import Optional, Union
from typing_extensions import get_args

logging.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 invalid list[int]) and the permissive str type 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 use Vivifiable objects (preferred approaches) or alternatively check a call to get_args yourself 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.

Licence

Copyright © 2022 Adam D Walker

Licensed 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 at http://www.apache.org/licenses/LICENSE-2.0

Unless 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vivify-1.0.1.tar.gz (11.5 kB view details)

Uploaded Source

Built Distribution

vivify-1.0.1-py3-none-any.whl (11.6 kB view details)

Uploaded Python 3

File details

Details for the file vivify-1.0.1.tar.gz.

File metadata

  • Download URL: vivify-1.0.1.tar.gz
  • Upload date:
  • Size: 11.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.14 CPython/3.9.12 Linux/5.17.5-051705-generic

File hashes

Hashes for vivify-1.0.1.tar.gz
Algorithm Hash digest
SHA256 92e872b563ab201174a21eb67d8650580bd34b9bf306af154d168d0759284f6d
MD5 11e857f142bfab19bcaa3b6336f009f1
BLAKE2b-256 c3dbfe18cb5351adbb383b8fb1fbc55cee02cdcc762ea3e8751a5c6e6076aa0d

See more details on using hashes here.

File details

Details for the file vivify-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: vivify-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 11.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.14 CPython/3.9.12 Linux/5.17.5-051705-generic

File hashes

Hashes for vivify-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c9ec75268f95ce2c46ea7d9fc11d6f29589fb22cfbdb94139db51535d8e1097d
MD5 4fc0c40c167cb5dcbbe20d4484e26e1b
BLAKE2b-256 3c87851dd3b821b849025787c7d988891961c263222fa55ef6b25a5edca7017f

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page