Skip to main content

Dictionary wrapper library

This Python library implements dictionary-like objects (precisely implementing the collections.abc.MutableMapping interface) with specialized properties. At the moment, two classes are defined:

  • DictWrapper: is a very simple child of collections.UserDict, a dictionary-like object which is easier to subclass.
  • NestedMapping: a structure to easily navigate the leaves of arborescent structures where dictionaries contain subdictionaries.

DictWrapper

There is not much to say about the DictWrapper class: it inherits from collections.UserDict and therefore provides

  • an internal dictionary .data
  • MutableMapping methods to access this dictionary: __getitem__, __setitem__, __len__, __contains__, __eq__, __ne__, keys, items, values
  • extra methods beyond that interface: __copy__ and __copy__
  • The __repr__ method returns <classname>(<data.__repr__()>)

NestedMapping

The NestedMapping class deserves some explanation. A high-level description is that it treats nested structures like a tree and exposes the leaf-level mappings like a flat dictionary. Explicitly, consider the following structure:

from dictwrapper.nested import  NestedMapping

tree = NestedMapping({
    "top leaf": "top leaf label",              # depth 0
    "branch": NestedMapping({                  # depth 0
        "lower leaf": "lower leaf label",      # depth 1
        "lower branch": NestedMapping({        # depth 1
            "lowest leaf": "lowest leaf label" # depth 2 
            })    
        }),
    "other branch": NestedMapping({            # depth 0
        "other leaf": "other leaf label"       # depth 1
    })
})

which can be represented as follow

root:               tree___________________
                    /   \                  \
depth 0:    top leaf     branch             other branch         
                        /      \                   |
depth 1:      lower leaf       lower branch      other leaf
                              /
depth 2:           lowest leaf

from a user point of view, the object tree behaves exactly like the following dictionary:

tree = {
    "top leaf": "top leaf label",              
    "lower leaf": "lower leaf label",
    "lowest leaf": "lowest leaf label",
    "other leaf": "other leaf label"
}

values can be accessed, edited or added by subscripting the object with [], iterating over it yields the sequence of its leaf keys, leaf keys can be checked for membership using the in operator, keys, items and values are accessible.

Subscripting on read and write fails when multiple keys match the request. When setting the value assocated to a key, if this key exists at any level, the corresponding value is replaced. If the key is not found anywhere in the structure, it is added as a top-level leaf.

The default creation mode is from an object convertible to a dictionary by calling dict on it. The class creator method has two optional parameters: recursive and check, both defaulting to True. If recursive is True, the creator goes through the dictionary structure and converts any sub-dictionary to a NestedMapping, otherwise they are left as they are. If check is True, the creator verifies the structure after instantiation and looks for any repeated keys at any levels and throws an exception if any are found. Since this structure is intended to hold configurations, YAML importation with pyyaml is also included using NestedMapping.from_yaml(yaml_file_path, loader=yaml.Loader, recursive=True, check=True) and NestedMapping.from_yaml_stream(stream, loader=yaml.Loader, recursive=True, check=True).

Finally, again with the application to configurations, calling the .to_dict method yields a vanilla dictionary that can be passed as function arguments using the ** operator.

Why would one use this?

The reason I wrote this is to define manipulate involved configurations with nested parameters passed to attribute objects. The main working paradigm is to have a standard working setup defined in some config file with the whole hierarchy of parameters, but being able to easily change some details of the hierarchy during experimentation.

For example, let us say a class ObjectA has an attribute of class ObjectB and that they can both be instantiated through ObjectA(paramA1=valueA1, ...., paramAN=valueAN, Bparams={"paramB1": valueB1, ...}) which calls ObjectB(**BParams), we can then define a default configuration as

DefaultABConfig = NestedConfig({
    "paramA1":valueA1,
    ...
    "paramAN": valueAN,
    "Bparams": {
        "paramB1": value1,
        ...    
}
})

And then edit some parameter in objectB by calling DefaultABConfig["paramB12"] = 42. When several layers are involved and the parameters are transparent enough to understand which level they belong to, this makes writing and reading scripts easier.

Metadata

Release files for dictwrapper 1.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dictwrapper 1.6
File Size Uploaded Provenance
dictwrapper-1.6.tar.gz 5.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for dictwrapper 1.6
File Interpreter ABI Platform
dictwrapper-1.6-py3-none-any.whl Python 3 none any Details

Total release size: 12.3 kB

Release files / dictwrapper-1.6.tar.gz

Download URL dictwrapper-1.6.tar.gz
Size 5.9 kB
Tags Source
SHA-256 checksum
How to use checksums
87defad25babd3232810d5e0c44161da3c36db2c57e1322c7a60c8ab132204ed
BLAKE2b-256 checksum
How to use checksums
5c1280197a6719287cc6ffff09f67049ef826483b269dbfaaca26fd89116d01c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.6.0 importlib_metadata/4.8.2 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.9

Release files / dictwrapper-1.6-py3-none-any.whl

Download URL dictwrapper-1.6-py3-none-any.whl
Size 6.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2af4bcd24f028f5b32581c6afa21d567cf283c83ff8f3349a66668b22f2ea614
BLAKE2b-256 checksum
How to use checksums
b54817c07ee2fda6397c70d51f0eea4d5021ba2d18fb8f38f7b2c81562fdd292
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.6.0 importlib_metadata/4.8.2 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.9

Security for dictwrapper 1.6

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page