Skip to main content

MetaDict is a powerful dict subclass enabling (nested) attribute-style item access/assignment and IDE autocompletion support.

Project description

MetaDict

Enabling dot notation and IDE autocompletion

InstallationFeaturesDocumentationCompetitorsCitation

Python Version PyPI version CircleCI codecov License


MetaDict is designed to behave exactly like a dict while enabling (nested) attribute-style key access/assignment with IDE autocompletion support.

Many libraries claim to do the same, but fail in different ways (see Competitors).

Installation

$ pip install metadict

Features

  • Attribute-style key access and assignment (dot notation) with IDE autocompletion support
    from metadict import MetaDict
    
    cfg = MetaDict()
    cfg.optimizer = 'Adam'
    print(cfg.optimizer)
    >> Adam
    
    autocompletion demo
  • Nested key assignment similar to defaultdict from collections
    cfg = MetaDict(nested_assignment=True)
    cfg.model.type = 'Transformer' 
    print(cfg.model.type)
    >> Transformer
    
    # or restrict nested assignment via context manager
    cfg = MetaDict()
    with cfg.enabling_nested_assignment() as cfg:
        cfg.model.type = 'Transformer'
    cfg.new_model.type = 'MLP'
    >> AttributeError: 'MetaDict' object has no attribute 'new_model'
    
  • Is a dict
    dict_config = {'model': 'Transformer',
                   'optimizer': 'Adam'}    
    cfg = MetaDict(dict_config)
    print(isinstance(cfg, dict))
    >> True
    print(cfg == dict_config)
    >> True
    
  • Inbuilt json support
    import json
    
    cfg = MetaDict({'model': 'Transformer'})
    print(json.loads(json.dumps(cfg)))
    >> {'model': 'Transformer'}
    
  • Recursive conversion to dict
    cfg = MetaDict({'models': [{'name': 'Transformer'}, {'name': 'MLP'}]})
    print(cfg.models[0].name)
    >> Transformer
    
    cfg_dict = cfg.to_dict()
    print(type(cfg_dict['models'][0]))
    >> <class 'dict'>
    
    # Note: Appending a `dict` to a list within a `MetaDict` does not convert the `dict`.
    # MetaDict does not overwrite `list` so intercepting `append`. `extend`, etc. is currently not possible.
    # Simply wrap the appended or extended `dict` as a `MetaDict`.
    cfg.models.append({'name': 'RNN'})
    print(isinstance(cfg.models[-1], MetaDict))
    >> False
    
    cfg.models.append(MetaDict({'name': 'RNN'}))
    print(isinstance(cfg.models[-1], MetaDict))
    >> True
    
  • No namespace conflicts with inbuilt methods like items(), update(), etc.
    cfg = MetaDict()
    # Key 'items' is assigned as in a normal dict, but a UserWarning is raised
    cfg.items = [1, 2, 3]
    >> UserWarning: 'MetaDict' object uses 'items' internally. 'items' can only be accessed via `obj['items']`.
    print(cfg)
    >> {'items': [1, 2, 3]}
    print(cfg['items'])
    >> [1, 2, 3]
    
    # But the items method is not overwritten!
    print(cfg.items)
    >> <bound method Mapping.items of {'items': [1, 2, 3]}>
    print(list(cfg.items()))
    >> [('items', [1, 2, 3])]
    
  • References are preserved
    params = [1, 2, 3]    
    cfg = MetaDict({'params': params})
    print(cfg.params is params)
    >> True
    
    model_dict = {'params': params}
    cfg = MetaDict(model=model_dict)
    print(cfg.model.params is params)
    >> True
    
    # Note: dicts are recursively converted to MetaDicts, thus...
    print(cfg.model is model_dict)
    >> False
    print(cfg.model == model_dict)
    >> True
    

Documentation

Check the Test Cases for a complete overview of all MetaDict features.

Competitors

  • Addict
    • No key autocompletion in IDE
    • Nested key assignment cannot be turned off
    • Newly assigned dict objects are not converted to support attribute-style key access
    • Shadows inbuilt type Dict
  • Prodict
    • No key autocompletion in IDE without defining a static schema (similar to dataclass)
    • No recursive conversion of dict objects when embedded in list or other inbuilt iterables
  • AttrDict
    • No key autocompletion in IDE
    • Converts list objects to tuple behind the scenes
  • Munch
    • Inbuilt methods like items(), update(), etc. can be overwritten with obj.items = [1, 2, 3]
    • No recursive conversion of dict objects when embedded in list or other inbuilt iterables
  • EasyDict
    • Only strings are valid keys, but dict accepts all hashable objects as keys
    • Inbuilt methods like items(), update(), etc. can be overwritten with obj.items = [1, 2, 3]
    • Inbuilt methods don't behave as expected: obj.pop('unknown_key', None) raises an AttributeError

Citation

@article{metadict,
  title = {MetaDict - Enabling dot notation and IDE autocompletion},
  author = {Hillebrand, Lars},
  year = {2022},
  publisher = {GitHub},
  journal = {GitHub repository},
  howpublished = {\url{https://github.com/LarsHill/metadict}},
}

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

metadict-0.1.3.tar.gz (6.8 kB view hashes)

Uploaded Source

Built Distribution

metadict-0.1.3-py3-none-any.whl (11.1 kB view hashes)

Uploaded Python 3

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