metadict


Namemetadict JSON
Version 0.1.5 PyPI version JSON
download
home_pagehttps://github.com/LarsHill/metadict/
SummaryMetaDict is a powerful dict subclass enabling (nested) attribute-style item access/assignment and IDE autocompletion support.
upload_time2025-07-19 11:23:38
maintainerNone
docs_urlNone
authorLars Hillebrand
requires_python>=3.6
licenseApache-2.0
keywords dict attribute-style syntax nesting auto-completion
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <div align="center">
<h1>MetaDict</h1>

_Enabling dot notation and IDE autocompletion_

<p align="center">
<a href="#installation">Installation</a> •
  <a href="#features">Features</a> •
<a href="#documentation">Documentation</a> •
  <a href="#competitors">Competitors</a> •
  <a href="#citation">Citation</a>
</p>

[![Python Version](https://img.shields.io/badge/python-3.6%20%7C%203.7%20%7C%203.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue.svg)](https://www.python.org/downloads/release/python-360/)
[![PyPI version](https://badge.fury.io/py/metadict.svg?dummy=unused)](https://badge.fury.io/py/metadict)
[![CircleCI](https://circleci.com/gh/LarsHill/metadict/tree/main.svg?style=shield)](https://circleci.com/gh/LarsHill/metadict/tree/main)
[![codecov](https://codecov.io/gh/LarsHill/metadict/branch/main/graph/badge.svg?token=XG4UDWF8RE)](https://codecov.io/gh/LarsHill/metadict)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

</div>

---

**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 <a href="#competitors">Competitors</a>). 

## Installation

```bash
$ pip install metadict
```
## Features

- Attribute-style key access and assignment (dot notation) with IDE autocompletion support
   ```python
   from metadict import MetaDict
   
   cfg = MetaDict()
   cfg.optimizer = 'Adam'
   print(cfg.optimizer)
   >> Adam
   ```
   ![autocompletion demo](/autocompletion.png?raw=true "Autocompletion demo")
- Nested key assignment similar to `defaultdict` from `collections`
   ```python
   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`
   ```python
   dict_config = {'model': 'Transformer',
                  'optimizer': 'Adam'}    
   cfg = MetaDict(dict_config)
   print(isinstance(cfg, dict))
   >> True
   print(cfg == dict_config)
   >> True
   ```
- Inbuilt `json` support
   ```python
   import json
       
   cfg = MetaDict({'model': 'Transformer'})
   print(json.loads(json.dumps(cfg)))
   >> {'model': 'Transformer'}
   ```
- Recursive conversion to `dict`
   ```python  
   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.
   ```python  
   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
   ```python
   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](https://github.com/LarsHill/metadict/blob/main/tests/test_metadict.py) for a complete overview of all **MetaDict** features.


## Competitors
- [Addict](https://github.com/mewwts/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](https://github.com/ramazanpolat/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](https://github.com/bcj/AttrDict)
  - No key autocompletion in IDE
  - Converts `list` objects to `tuple` behind the scenes
- [Munch](https://github.com/Infinidat/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](https://github.com/makinacorpus/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}},
}
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/LarsHill/metadict/",
    "name": "metadict",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": null,
    "keywords": "dict, attribute-style syntax, nesting, auto-completion",
    "author": "Lars Hillebrand",
    "author_email": "hokage555@web.de",
    "download_url": "https://files.pythonhosted.org/packages/d1/e1/b1831cf30286259e8250c9ec2814cc27c1110a91437723f85fb5b74138ab/metadict-0.1.5.tar.gz",
    "platform": null,
    "description": "<div align=\"center\">\n<h1>MetaDict</h1>\n\n_Enabling dot notation and IDE autocompletion_\n\n<p align=\"center\">\n<a href=\"#installation\">Installation</a> \u2022\n  <a href=\"#features\">Features</a> \u2022\n<a href=\"#documentation\">Documentation</a> \u2022\n  <a href=\"#competitors\">Competitors</a> \u2022\n  <a href=\"#citation\">Citation</a>\n</p>\n\n[![Python Version](https://img.shields.io/badge/python-3.6%20%7C%203.7%20%7C%203.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12-blue.svg)](https://www.python.org/downloads/release/python-360/)\n[![PyPI version](https://badge.fury.io/py/metadict.svg?dummy=unused)](https://badge.fury.io/py/metadict)\n[![CircleCI](https://circleci.com/gh/LarsHill/metadict/tree/main.svg?style=shield)](https://circleci.com/gh/LarsHill/metadict/tree/main)\n[![codecov](https://codecov.io/gh/LarsHill/metadict/branch/main/graph/badge.svg?token=XG4UDWF8RE)](https://codecov.io/gh/LarsHill/metadict)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n\n</div>\n\n---\n\n**MetaDict** is designed to behave exactly like a `dict` while enabling (nested) attribute-style key access/assignment with IDE autocompletion support. \n\nMany libraries claim to do the same, but fail in different ways (see <a href=\"#competitors\">Competitors</a>). \n\n## Installation\n\n```bash\n$ pip install metadict\n```\n## Features\n\n- Attribute-style key access and assignment (dot notation) with IDE autocompletion support\n   ```python\n   from metadict import MetaDict\n   \n   cfg = MetaDict()\n   cfg.optimizer = 'Adam'\n   print(cfg.optimizer)\n   >> Adam\n   ```\n   ![autocompletion demo](/autocompletion.png?raw=true \"Autocompletion demo\")\n- Nested key assignment similar to `defaultdict` from `collections`\n   ```python\n   cfg = MetaDict(nested_assignment=True)\n   cfg.model.type = 'Transformer' \n   print(cfg.model.type)\n   >> Transformer\n   \n   # or restrict nested assignment via context manager\n   cfg = MetaDict()\n   with cfg.enabling_nested_assignment() as cfg:\n       cfg.model.type = 'Transformer'\n   cfg.new_model.type = 'MLP'\n   >> AttributeError: 'MetaDict' object has no attribute 'new_model'\n   ```\n- Is a `dict`\n   ```python\n   dict_config = {'model': 'Transformer',\n                  'optimizer': 'Adam'}    \n   cfg = MetaDict(dict_config)\n   print(isinstance(cfg, dict))\n   >> True\n   print(cfg == dict_config)\n   >> True\n   ```\n- Inbuilt `json` support\n   ```python\n   import json\n       \n   cfg = MetaDict({'model': 'Transformer'})\n   print(json.loads(json.dumps(cfg)))\n   >> {'model': 'Transformer'}\n   ```\n- Recursive conversion to `dict`\n   ```python  \n   cfg = MetaDict({'models': [{'name': 'Transformer'}, {'name': 'MLP'}]})\n   print(cfg.models[0].name)\n   >> Transformer\n   \n   cfg_dict = cfg.to_dict()\n   print(type(cfg_dict['models'][0]))\n   >> <class 'dict'>\n  \n   # Note: Appending a `dict` to a list within a `MetaDict` does not convert the `dict`.\n   # MetaDict does not overwrite `list` so intercepting `append`. `extend`, etc. is currently not possible.\n   # Simply wrap the appended or extended `dict` as a `MetaDict`.\n   cfg.models.append({'name': 'RNN'})\n   print(isinstance(cfg.models[-1], MetaDict))\n   >> False\n   \n   cfg.models.append(MetaDict({'name': 'RNN'}))\n   print(isinstance(cfg.models[-1], MetaDict))\n   >> True\n   ```\n- No namespace conflicts with inbuilt methods like `items()`, `update()`, etc.\n   ```python  \n   cfg = MetaDict()\n   # Key 'items' is assigned as in a normal dict, but a UserWarning is raised\n   cfg.items = [1, 2, 3]\n   >> UserWarning: 'MetaDict' object uses 'items' internally. 'items' can only be accessed via `obj['items']`.\n   print(cfg)\n   >> {'items': [1, 2, 3]}\n   print(cfg['items'])\n   >> [1, 2, 3]\n   \n   # But the items method is not overwritten!\n   print(cfg.items)\n   >> <bound method Mapping.items of {'items': [1, 2, 3]}>\n   print(list(cfg.items()))\n   >> [('items', [1, 2, 3])]\n   ```\n- References are preserved\n   ```python\n   params = [1, 2, 3]    \n   cfg = MetaDict({'params': params})\n   print(cfg.params is params)\n   >> True\n   \n   model_dict = {'params': params}\n   cfg = MetaDict(model=model_dict)\n   print(cfg.model.params is params)\n   >> True\n   \n   # Note: dicts are recursively converted to MetaDicts, thus...\n   print(cfg.model is model_dict)\n   >> False\n   print(cfg.model == model_dict)\n   >> True\n   ```\n\n## Documentation\n\nCheck the [Test Cases](https://github.com/LarsHill/metadict/blob/main/tests/test_metadict.py) for a complete overview of all **MetaDict** features.\n\n\n## Competitors\n- [Addict](https://github.com/mewwts/addict)\n  - No key autocompletion in IDE\n  - Nested key assignment cannot be turned off\n  - Newly assigned `dict` objects are not converted to support attribute-style key access\n  - Shadows inbuilt type `Dict`\n- [Prodict](https://github.com/ramazanpolat/prodict)\n  - No key autocompletion in IDE without defining a static schema (similar to `dataclass`)\n  - No recursive conversion of `dict` objects when embedded in `list` or other inbuilt iterables\n- [AttrDict](https://github.com/bcj/AttrDict)\n  - No key autocompletion in IDE\n  - Converts `list` objects to `tuple` behind the scenes\n- [Munch](https://github.com/Infinidat/munch)\n  - Inbuilt methods like `items()`, `update()`, etc. can be overwritten with `obj.items = [1, 2, 3]` \n  - No recursive conversion of `dict` objects when embedded in `list` or other inbuilt iterables\n- [EasyDict](https://github.com/makinacorpus/easydict)\n  - Only strings are valid keys, but `dict` accepts all hashable objects as keys\n  - Inbuilt methods like `items()`, `update()`, etc. can be overwritten with `obj.items = [1, 2, 3]`\n  - Inbuilt methods don't behave as expected: `obj.pop('unknown_key', None)` raises an `AttributeError`\n\n\n## Citation\n\n```\n@article{metadict,\n  title = {MetaDict - Enabling dot notation and IDE autocompletion},\n  author = {Hillebrand, Lars},\n  year = {2022},\n  publisher = {GitHub},\n  journal = {GitHub repository},\n  howpublished = {\\url{https://github.com/LarsHill/metadict}},\n}\n```\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "MetaDict is a powerful dict subclass enabling (nested) attribute-style item access/assignment and IDE autocompletion support.",
    "version": "0.1.5",
    "project_urls": {
        "Download": "https://github.com/LarsHill/metadict/",
        "Homepage": "https://github.com/LarsHill/metadict/"
    },
    "split_keywords": [
        "dict",
        " attribute-style syntax",
        " nesting",
        " auto-completion"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "5b62526f926e3cfbc0cd136480b5902f920502aa41a0c914db3e20ea2804d64c",
                "md5": "a3ea685bda910bae69d1dfae4dc40fe9",
                "sha256": "e374cf55cd7e182135f35c50f9c4e83b8f0d70e74b626f6c4499a01267ad0f80"
            },
            "downloads": -1,
            "filename": "metadict-0.1.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "a3ea685bda910bae69d1dfae4dc40fe9",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.6",
            "size": 11192,
            "upload_time": "2025-07-19T11:23:37",
            "upload_time_iso_8601": "2025-07-19T11:23:37.744881Z",
            "url": "https://files.pythonhosted.org/packages/5b/62/526f926e3cfbc0cd136480b5902f920502aa41a0c914db3e20ea2804d64c/metadict-0.1.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "d1e1b1831cf30286259e8250c9ec2814cc27c1110a91437723f85fb5b74138ab",
                "md5": "a555cf9d90a1060a31493316b4ee8fa5",
                "sha256": "4ebd972a4bd1d22e72a158bfc6ff8d497deab7ab220fa27ad128fcee4f54f300"
            },
            "downloads": -1,
            "filename": "metadict-0.1.5.tar.gz",
            "has_sig": false,
            "md5_digest": "a555cf9d90a1060a31493316b4ee8fa5",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 10880,
            "upload_time": "2025-07-19T11:23:38",
            "upload_time_iso_8601": "2025-07-19T11:23:38.913845Z",
            "url": "https://files.pythonhosted.org/packages/d1/e1/b1831cf30286259e8250c9ec2814cc27c1110a91437723f85fb5b74138ab/metadict-0.1.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-19 11:23:38",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "LarsHill",
    "github_project": "metadict",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "circle": true,
    "lcname": "metadict"
}
        
Elapsed time: 1.27918s