{ "info": { "author": "Adamos Kyriakou", "author_email": "somada141@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 2 - Pre-Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5" ], "description": "========\nvivodict\n========\n\n\n.. image:: https://img.shields.io/pypi/v/vivodict.svg\n :target: https://pypi.python.org/pypi/vivodict\n\n.. image:: https://img.shields.io/travis/somada141/vivodict.svg\n :target: https://travis-ci.org/somada141/vivodict\n\n.. image:: https://readthedocs.org/projects/vivodict/badge/?version=latest\n :target: https://vivodict.readthedocs.io/en/latest/?badge=latest\n :alt: Documentation Status\n\n\nThis package provides a simple implementation of an `auto-vivified\n`_ Python ``dict``, i.e., a\ndictionary where accessing a missing key doesn't raise the standard ``KeyError``\nexception but instead implicitly creates and returns an empty auto-vivified\n``dict`` under that key.\n\n\nFeatures\n--------\n\n* Auto-vivified ``VivoDict`` class derived from the standard Python ``dict``\n class (no third-party dependencies).\n* Auto-vivification of arbitrarily-nested ``dict`` objects.\n* Convenience methods for ``flatten``, ``replace``, and ``apply`` operations.\n* Free software: MIT license\n* Documentation: https://vivodict.readthedocs.io.\n\nMotivation\n----------\n\nMy primary motivation for developing this package is because it contained a\npiece of code I kept copy-pasting like a bloody caveman between projects.\n\nMy typical use-cases for this code include:\n\n* Wrap the decoded JSON ``dict`` from crummy APIs without a schema that just\n decide to drop keys for which the values are ``null`` resulting in code with\n nested ``if \"key\" in result:``. This allowed me to either retrieve the value\n if it was there or at least arriving at an empty ``dict`` which evaluates to\n ``False`` when mapping their half-formed data to my own data-structures.\n* Create arbitrarily-nested dictionaries of code stats that I can keep organized\n as I like while using in the code and then quickly ``flatten`` to a Graphite\n compatible format prior to posting them to ... well Graphite.\n\nBasic Usage\n-----------\n\nThis would be the typical Python ``dict`` behaviour when accessing a missing\nkey::\n\n >>> d = {\"a\": 1, \"b\": 2}\n >>> d[\"a\"]\n 1\n >>> d[\"missing\"]\n ---------------------------------------------------------------------------\n KeyError Traceback (most recent call last)\n in ()\n ----> 1 d[\"missing\"]\n\n KeyError: 'missing'\n\nWhile if we were using a ``VivoDict``, then upon accessing a missing key we\nwould be provided with an implicitly created empty ``VivoDict`` as such::\n\n >>> from vivodict import VivoDict\n >>> d = VivoDict.vivify({\"a\": 1, \"b\": 2})\n >>> d[\"a\"]\n 1\n >>> d[\"missing\"]\n {}\n\n.. note::\n\n Note that instantiation above is not performed simply by passing an existing\n ``dict`` to ``VivoDict`` but instead through the ``vivify`` class method\n which can recursively convert any arbitrarily-nested ``dict`` to a\n ``VivoDict``.\n\nNow, while the above doesn't seem to offer anything a simple ``try-except`` or\na ``if \"key\" not in d`` wouldn't offer, the ``VivoDict`` becomes useful when\ndealing with arbitrarily nested dictionaries where there may be several levels\nof missing keys. For example::\n\n >>> from vivodict import VivoDict\n >>> d = VivoDict({\"a\": 1, \"b\": {\"c\": 2}, \"d\": {\"e\": {\"f\": 3}}})\n >>> d[\"a\"]\n 1\n >>> d[\"b\"][\"c\"]\n 2\n >>> d[\"d\"][\"e\"][\"f\"]\n 3\n >>> d[\"i\"][\"am\"][\"missing\"][\"eh\"] = 4\n >>> d\n {'a': 1,\n 'b': {'c': 2},\n 'd': {'e': {'f': 3}},\n 'i': {'am': {'missing': {'eh': 4}}}}\n\nSo, as can be seen, having auto-vivification allows one to nest keys and values\nto whatever degree.\n\n.. warning::\n\n The primary caveat of the above functionality is that ``VivoDict`` are very\n forgiving when it comes to typos which can leads to weird errors. A\n mistyped key will simply create a new ``VivoDict`` and will allow you to go\n down some rabbithole of erroneously typed keys your linter won't get you out\n of.\n\nConvenience Functions\n---------------------\n\nIn addition to the above, a few basic convenience methods have been built into\nthe ``VivoDict`` class, mostly cause they make my life easier and lazier.\n\n\nflatten\n^^^^^^^\n\nAs I mentioned prior one of my typical use-cases for ``vivodict`` is using it\nto store nested metrics which I then post to Graphite via simple HTTP requests.\n\nGraphite, however, bases its structure on ``.`` delimited names where anything\npreceding a ``.`` is considered to be a metric folder with the last token being\nthe metric itself.\n\nThus, I needed a quick way to flatten a nested ``dict`` into a Graphite\ncompatible version.\n\nThe ``flatten`` method does exactly that::\n\n >>> d = VivoDict.vivify({\"a\": 1, \"b\": {\"c\": 2}, \"d\": {\"e\": {\"f\": 3}}})\n >>> d.flatten()\n {'a': 1, 'b.c': 2, 'd.e.f': 3}\n\nreplace\n^^^^^^^\n\nFollowing the same premise as with ``flatten`` I needed to quickly 'reset' my\nmetrics back to 0 between posting cycles.\n\nHence, ``replace`` will replace all 'leaf' node values in what is essentially a\ntree with a given ``value``::\n\n >>> d = VivoDict.vivify({\"a\": 1, \"b\": {\"c\": 2}, \"d\": {\"e\": {\"f\": 3}}})\n >>> d.replace(replace_with=0)\n >>> d\n {'a': 0, 'b': {'c': 0}, 'd': {'e': {'f': 0}}}\n\n.. warning::\n\n As you may have noticed from the above snippet, the ``replace`` method\n performs an **in-place** replacement instead of returning a copy of the\n original ``VivoDict`` with replaced values.\n\nShould you need to maintain an original copy I'd suggest you use the ``copy``\npackage and its ``deepcopy`` function (cause Python passes by reference) as\nsuch::\n\n >>> import copy\n >>> original = VivoDict.vivify({\"a\": 1, \"b\": {\"c\": 2}, \"d\": {\"e\": {\"f\": 3}}})\n >>> modified = copy.deepcopy(original)\n >>> modified.replace(replace_with=0)\n >>> original\n {'a': 1, 'b': {'c': 2}, 'd': {'e': {'f': 3}}}\n >>> modified\n {'a': 0, 'b': {'c': 0}, 'd': {'e': {'f': 0}}}\n\n\napply\n^^^^^\n\nLastly, I often had to modify all values through a given function, typically\ndivide them by a number of observation for average metrics which can be easily\ndone through the ``apply`` method which can take any ``callable`` as an\nargument and replace the original value with its return-value::\n\n >>> d = VivoDict.vivify({\"a\": 1, \"b\": {\"c\": 2}, \"d\": {\"e\": {\"f\": 3}}})\n >>> def double(value):\n >>> return value * 2\n >>> d.apply(double)\n >>> d\n {'a': 2, 'b': {'c': 4}, 'd': {'e': {'f': 6}}}\n >>> d.apply(lambda value: value / 2)\n {'a': 1, 'b': {'c': 2}, 'd': {'e': {'f': 3}}}\n\n.. warning::\n\n Much like ``replace``, the ``apply`` method replaces values **in-place**.\n\n\n=======\nHistory\n=======\n\n0.3.1 (2017-07-23)\n------------------\n\n* README.rst: Fixed minor formatting typo.\n\n0.3.0 (2017-07-23)\n------------------\n\n* Cleanup the docos and removed a bunch of the unnecessary stuff.\n\n0.2.0 (2017-07-23)\n------------------\n\n* Added more unit-tests and improved docstrings.\n\n0.1.1 (2017-07-23)\n------------------\n\n* Fixed issues with the Python dependencies.\n\n0.1.0 (2017-07-23)\n------------------\n\n* First release on PyPI.\n\n\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/somada141/vivodict", "keywords": "vivodict", "license": "MIT license", "maintainer": "", "maintainer_email": "", "name": "vivodict", "package_url": "https://pypi.org/project/vivodict/", "platform": "", "project_url": "https://pypi.org/project/vivodict/", "project_urls": { "Homepage": "https://github.com/somada141/vivodict" }, "release_url": "https://pypi.org/project/vivodict/0.3.1/", "requires_dist": null, "requires_python": "", "summary": "Auto-vivified arbitrarily-nested dictionary (`dict`) classes.", "version": "0.3.1" }, "last_serial": 3042774, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "4bca61966ae2a0131cee3439afb3c9e5", "sha256": "01b584eaf74c6ac9deda7d59caf1d570cc4aa7bbeb7a09b081afcbf7b7d5f549" }, "downloads": -1, "filename": "vivodict-0.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "4bca61966ae2a0131cee3439afb3c9e5", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 5516, "upload_time": "2017-07-23T06:09:24", "url": "https://files.pythonhosted.org/packages/55/d5/44814610b8fd53edc06594cda9b5a3e6f8701f7b000ae2fc6e5cfe66b48c/vivodict-0.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3e36fa5b24a53cfae8053d10e1a644a1", "sha256": "b345f92f0fa11f98c6cba85f79542c4d5a87f3051df324ac4557819332eef5f8" }, "downloads": -1, "filename": "vivodict-0.1.0.tar.gz", "has_sig": false, "md5_digest": "3e36fa5b24a53cfae8053d10e1a644a1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13642, "upload_time": "2017-07-23T06:09:26", "url": "https://files.pythonhosted.org/packages/84/af/2f92485f659239dbb604941453de930dd0d28fc432462fb55f28e8ccf55d/vivodict-0.1.0.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "5abb63c159b7b1cbad434c9a7e9e506c", "sha256": "9d411b3f70f9b852b80bfe1b8e12ebdd5b09d1de21021ad5597d61c0bd8395b3" }, "downloads": -1, "filename": "vivodict-0.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "5abb63c159b7b1cbad434c9a7e9e506c", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 5694, "upload_time": "2017-07-23T06:46:45", "url": "https://files.pythonhosted.org/packages/06/14/f7671c653f377fa126f194040f002ba46d89d6b573f8bce43be9a6a8514b/vivodict-0.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "20a17819577da008941ba78e3ff2a268", "sha256": "334bdecf5b564a88ea0522fcb02add08e966e66f2617bcaf1735955fa7078305" }, "downloads": -1, "filename": "vivodict-0.2.0.tar.gz", "has_sig": false, "md5_digest": "20a17819577da008941ba78e3ff2a268", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13791, "upload_time": "2017-07-23T06:46:47", "url": "https://files.pythonhosted.org/packages/65/52/f37b8cb9c6ec67659c1edabb9b9ce97f15cba2bb3c28a0a27c2d9ff2b6d1/vivodict-0.2.0.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "7fb7617564436f5c8aee622b782c3dd2", "sha256": "4a9c665e52dddcd04f050bec3240c2c72f83f0372acfefc307bece7c8c2bae57" }, "downloads": -1, "filename": "vivodict-0.3.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "7fb7617564436f5c8aee622b782c3dd2", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10206, "upload_time": "2017-07-23T08:18:54", "url": "https://files.pythonhosted.org/packages/e4/79/75c82effcd1b86eb64205fd8e1ac9e4ccc3e48c254c6923f566a6d4613c9/vivodict-0.3.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f83fa8410ff7b6ea6cf2f168a2893cba", "sha256": "341003bc8472376c0e487b741e9ddb056b53db8378524dfc46d99c799265af1c" }, "downloads": -1, "filename": "vivodict-0.3.0.tar.gz", "has_sig": false, "md5_digest": "f83fa8410ff7b6ea6cf2f168a2893cba", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14828, "upload_time": "2017-07-23T08:18:55", "url": "https://files.pythonhosted.org/packages/6c/e6/eca05be88a4a4a9a3267786405b2333d6936c7fcbdf1cc84dcd8a99f7168/vivodict-0.3.0.tar.gz" } ], "0.3.1": [ { "comment_text": "", "digests": { "md5": "83cb9cb5506bbc2c27c64133294d909b", "sha256": "4bab31869bdcf005a7e5258d71109e48940703d71af3fd7d02eedda828e05c5c" }, "downloads": -1, "filename": "vivodict-0.3.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "83cb9cb5506bbc2c27c64133294d909b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10260, "upload_time": "2017-07-23T08:55:34", "url": "https://files.pythonhosted.org/packages/67/02/57ade8fd3d8984a3cee6c02adae4a0c287cdf1445a69684f3c3c73be4076/vivodict-0.3.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9725aeba393f8e19b0bff49fa4faa688", "sha256": "1e4c0d2001bb424e514cab14ea56d31a4d770958973bdf7366ff90dfb9bc81a1" }, "downloads": -1, "filename": "vivodict-0.3.1.tar.gz", "has_sig": false, "md5_digest": "9725aeba393f8e19b0bff49fa4faa688", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14850, "upload_time": "2017-07-23T08:55:35", "url": "https://files.pythonhosted.org/packages/3a/f5/2233f19ff549273613c0d7a12947e8d73739007fb2dcf90625e78686ab41/vivodict-0.3.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "83cb9cb5506bbc2c27c64133294d909b", "sha256": "4bab31869bdcf005a7e5258d71109e48940703d71af3fd7d02eedda828e05c5c" }, "downloads": -1, "filename": "vivodict-0.3.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "83cb9cb5506bbc2c27c64133294d909b", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 10260, "upload_time": "2017-07-23T08:55:34", "url": "https://files.pythonhosted.org/packages/67/02/57ade8fd3d8984a3cee6c02adae4a0c287cdf1445a69684f3c3c73be4076/vivodict-0.3.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9725aeba393f8e19b0bff49fa4faa688", "sha256": "1e4c0d2001bb424e514cab14ea56d31a4d770958973bdf7366ff90dfb9bc81a1" }, "downloads": -1, "filename": "vivodict-0.3.1.tar.gz", "has_sig": false, "md5_digest": "9725aeba393f8e19b0bff49fa4faa688", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 14850, "upload_time": "2017-07-23T08:55:35", "url": "https://files.pythonhosted.org/packages/3a/f5/2233f19ff549273613c0d7a12947e8d73739007fb2dcf90625e78686ab41/vivodict-0.3.1.tar.gz" } ] }