Skip to main content

I - Dict

picture picture

Dictionary with declared structure in Python

Tiny extension for defaultdict Python's class. Use this library if you need to ensure or force concrete structure for your dictionary and use it as normal dictionary then.


Install

Install from PyPI:

pip install idict-schema

or from sources:

pip install .

After installation, import from:

from idict import Idict

Overview

You can provide desired dictionary's structure and specify action for non desired usage e.g. specify action if someone uses unexpected key or value.

You can also specify required and/or default values for specified keys.

1.0 Contract

  • Distribution name: idict-schema
  • Import path: idict (from idict import Idict)
  • missing_keys = THROW is enforced for [] =, update, setdefault, |, and |=
  • Mandatory keys (...) are validated against the declared schema (validate())
  • copy.copy(idict_obj) is supported
  • pickle serialization is currently not supported and raises a clear TypeError
  • hash_code() returns Base64 of repr(dict(...)) (it is not a cryptographic hash)

General usage

from idict import Idict

desired_default_structure = {
    'a': 1,
    'c': None
}

options = {
    "missing_keys": Idict.OPT.THROW,
    "ellipsis_as_mandatory": True
}

my_dict = Idict(desired_default_structure, options)

my_dict['a'] = 1

print(repr(my_dict))
# {'a': 1, 'c': None}

Options

[ missing_keys ] - action if unspecified key usage

options = {
    "missing_keys": Idict.OPT.ALLOW
}

possible options: Idict.OPT.

  • ALLOW [default value] - allow all other keys and just add to the dictionary.

  • IGNORE - ignore keys not available in specified interface and allow only specified keys. Always keep the same, desired structure. Ignore tries to change dictionary structure.

  • THROW - throw an exception KeyNotAllowedException if someone tries to set key-value for unspecified key. Throw an exception ValueNotAllowedException if someone tries to change specified key-value structure. See examples below.

    Key not allowed:

        my_dict = Idict({'a': None, 'b': {'bb1': None}}, {"missing_keys": Idict.OPT.THROW})
        my_dict['non_existing_key'] = 123
    
        '''
        KeyNotAllowedException
        [Key Error] You are trying to set value for key <non_existing> for your Idict 
        <your_dict:Idict> but this key is disallowed and doesnt exist in the provided interface
        '''
    

    Trying to overwritte expected structure and set integer where dictionary should be:

    my_dict = Idict({'a': {'aa': {'aaa': 1}}}, options={"missing_keys": Idict.OPT.THROW})
    my_dict['a']['aa'] = 123
    
    '''
    ValueNotAllowedException: 
    [Value Error] Trying to set value <123> for object , key <aa> 
    but in provided interface there is a dictionary under this key - {'aa': {'aaa': 1}}.
    You cannot change expected objects structure
    '''
    

[ ellipsis_as_mandatory ] - [default = True] use Ellipsis (...) as a tag for mandatory keys.
If this option is settled to True then, upon validation, library will check if every key with Ellipsis value has new value settled. Dictionary will be valid as long as every value tagged by ... has new value. Otherwise dict.validate() will throw an excaption MandatoryKeyValueException.

options = {
    "ellipsis_as_mandatory": True
}

possible options:

  • True
  • False

Example:

# use Ellipsis - ... as a tag for mandatory values
my_dict = Idict({'a': {'aa': None}, 'b': ...}, options={"ellipsis_as_mandatory": True})

my_dict.validate()

# THROWS:
# MandatoryKeyValueException: Key value for key [b]
# is mandatory. Set value for this key or set default value in provided interface. 

my_dict['b'] = "anything"

my_dict.validate()
# OK, no exception, result = True

Examples

  • Allow specified and unspecified keys:

    Default structure and default values are specified in advance. We allow other key-value pairs, not only specified ones.

    my_dict = Idict({
        'a': 1,
        'b': 2,
        'c': {
            'cc': 3,
        },
        'd': {
            'dd': {
                'ddd': 4
            },
        },
    })
    
    # set/overwrite some values
    my_dict['a'] = 11
    my_dict['c']['cc'] = 33
    my_dict['d']['dd']['new-value'] = 44
    my_dict['e']['ee'] = 55
    
    print(repr(my_dict))
    # {'a': 11, 'b': 2, 'c': {'cc': 33}, 'd': {'dd': {'ddd': 4, 'new-value': 44}}, 'e': {'ee': 55}}
    
  • Ignore unexpected keys:

    Allow only specified structure, ignore all other key-value pairs.

    my_dict = Idict({
        'a': 1,
        'c': {
            'cc1': 3,
            'cc2': 4,
        }
    }, {
        "missing_keys": Idict.OPT.IGNORE,
    })
    
    # set/overwrite some values
    my_dict['a'] = 11
    my_dict['b'] = 22
    my_dict['c']['cc1'] = 33
    my_dict['d'] = 55
    
    
    print(repr(my_dict))
    # {'a': 11, 'c': {'cc1': 33, 'cc2': 4}}
    
  • Allow only specified keys usage or throw an exception KeyNotAllowedException

    Throw an exception (KeyNotAllowedException) in case of trying to set value for disallowed key:

    dict1 = Idict({
        'a': None,
        'b': {
            'bb1': None,
            'bb2': None
        }
    }, {
        "missing_keys": Idict.OPT.THROW
    })
    
    try:
       dict1['non_existing_key'] = "value"
    except KeyNotAllowedException as ex:
        print(ex)
        # [Key Error] You are trying to set value 
        # for key  for your Idict 
        #  but this key is disallowed 
        # and doesnt exist in the provided interface
    
  • Changing default/provided default dictionary's structure

        desired_structure = {
            'a': 'default value <a>',
            'b': {
                'bb1': 'default value ',
            }
        }
    
        my_dict = Idict(desired_structure, {
            "missing_keys": Idict.OPT.ALLOW
        })
    
        my_dict_ign = Idict(desired_structure, {
            "missing_keys": Idict.OPT.IGNORE
        })
    
        my_dict_thr = Idict(desired_structure, {
            "missing_keys": Idict.OPT.THROW
        })
    
        my_dict['b'] = 123
        print(repr(my_dict))
        # OK, result: {'a': 'default value <a>', 'b': 123}
    
        my_dict_ign['b'] = 123
        print(repr(my_dict_ign))
        # illegal trying to change desired dictionary structure
        # this operation will be ignored
        # OK, no exception, result: {'a': 'default value ', 'b': {'bb1': 'default value '}}
    
        my_dict_thr['b'] = 123
        # illegal trying to change desired dictionary structure
        # result: raise ValueNotAllowedException as below
        
        # ValueNotAllowedException: [Value Error] Trying to set value <123> 
        # for object <your_dict:Idict>, key <b> but in provided interface there 
        # is a dictionary under this key - <interface>
        # {'a': 'default value ', 'b': {'bb1': 'default value '}}. 
        # You cannot change expected objects structure
    
  • Validate dictionary, check mandatory keys.

    Check if all mandatory keys (marked by Ellipsis - ...) are overwritten/settled

    my_dict1 = Idict({
        'a': None,
        'b': {
            'bb1': None,
            'bb2': ...
        },
    })
    
    try:
        my_dict1.validate()
    except MandatoryKeyValueException as e:
        # Key value for key [b][bb2] is mandatory.
        # Set value for this key or set default value in provided interface.
        pass
    
    my_dict1['b']['bb2'] = 123
    
    print(repr(my_dict1))
    # no Exception, all mandatory keys have value settled
    # {'a': None, 'b': {'bb1': None, 'bb2': 123}}
        
    

Authors

  • Slawomir Hadas - author - Github

See more

See ./tests for more examples


Metadata

Release files for idict-schema 1.0.0

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

Source distribution (sdist)

Source distribution for idict-schema 1.0.0
File Size Uploaded
idict_schema-1.0.0.tar.gz 27.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for idict-schema 1.0.0
File Interpreter ABI Platform
idict_schema-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 52.3 kB

Release files / idict_schema-1.0.0.tar.gz

Download URL idict_schema-1.0.0.tar.gz
Size 27.4 kB
Tags Source
SHA-256 checksum
How to use checksums
ec13dc23946b17b1cd67f4dd9ef7ba18a32a1d632f6763de44cceccd4e316e3d
BLAKE2b-256 checksum
How to use checksums
5ea270dfc4426591c31e31d955e81781d54db1756c96dab576c7dbbfd6292377
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release files / idict_schema-1.0.0-py3-none-any.whl

Download URL idict_schema-1.0.0-py3-none-any.whl
Size 24.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
48b25b6292367cddee761182c04e23b34daa97b3257b273ef68eee4268337b34
BLAKE2b-256 checksum
How to use checksums
941b6953f14d961ad450ce509f9b3a54a99724bddbfb31961486602bc2adadbc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

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