{ "info": { "author": "Calvin Smith", "author_email": "sapientdust+uberdict@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Utilities" ], "description": "========\nuberdict\n========\n\n.. image:: https://travis-ci.org/eukaryote/uberdict.svg?branch=master\n :target: https://travis-ci.org/eukaryote/uberdict\n\n\n``uberdict.udict`` is a Python ``dict`` class that supports attribute-style\naccess and hierarchical keys:\n\n.. code-block:: python\n\n my_udict.result.status.code # is equivalent to:\n my_udict['result']['status']['code']\n\n my_udict.get('result.status.code', default) # is equivalent to:\n my_udict.get('result', {}).get('status', {}).get('code', default)\n\nTested under py27, py32, py33, py34, py35, py36, py37, and\npypy (Python2 and Python 3.5 pypy versions).\n\n\nKey Features\n------------\n\nEasy Conversion from/to plain dict\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe `__init__` method signature matches that of the stdlib's `dict`, so it can\nbe used as a drop-in replacement for `dict`. If you want to create a `udict`\nfrom a plain `dict` as a deep copy that converts every plain `dict` value at\nany level to an equivalent `udict`, use the `udict.fromdict` class method\n(and for the reverse direction, use the `todict` instance method of a `udict`\ninstance):\n\n.. code-block:: python\n\n d = {\n 'result': {\n 'status': {\n 'code': 200,\n 'reason': 'OK'\n }\n }\n }\n\n # shallow udict copy, like plain `dict` (the `result` value is the original `dict`)\n ud = udict(d)\n\n # deep udict copy that recursively converts `dict` to `udict`:\n ud = udict.fromdict(d)\n\n # convert back to plain `dict` (recursively)\n d = ud.todict()\n\n\nAttribute-Style Access\n~~~~~~~~~~~~~~~~~~~~~~\n\nThe values in a `udict` may be accessed as if they were attributes on the `udict`,\nlike normal Python objects:\n\n.. code-block:: python\n\n d = {\n 'result': {\n 'status': {\n 'code': 200,\n 'reason': 'OK'\n }\n }\n }\n ud = udict.fromdict(d)\n\n assert ud.result.status.code == ud['result']['status']['code']\n\n # setting an attribute on the `udict` instance works like a normal dict insertion\n ud.message = udict(lang='en', body='Hello, World!')\n\n assert 'message' in ud\n assert ud['message'] == ud.message\n\n\nThe standard Python attr methods (`hasattr`, `getattr`, `setattr`, and\n`delattr`) work as expected.\n\n.. code-block:: python\n\n # hasattr/getattr/setattr/delattr work as expected\n d = udict()\n assert not hasattr(d, 'foo')\n d.foo = 'foo'\n d['bar'] = 'bar'\n assert hasattr(d, 'foo')\n assert hasattr(d, 'bar')\n setattr(d, 'baz', 'bazbaz')\n assert 'baz' in d\n assert d['baz'] == 'bazbaz'\n delattr(d, 'baz')\n assert 'baz' not in d\n del d['foo'] # works too\n assert 'foo' not in d\n assert not hasattr(d, 'foo')\n\n\nNote: ``getattr`` and related functions don't interpret a `.` in keys in any\nspecial way, so you can always insert a key containing a `.` using `setattr`,\nand can retrieve the value for a key containing a `.` by using `getattr`.\n\n\n.. code-block:: python\n\n d = {\n 'a': {\n 'b': 'a->b'\n },\n 'a.b': 'a.b'\n }\n ud = udict.fromdict(d)\n setattr(ud, 'a.b', None) # doesn't touch 'a'\n assert ud['a.b'] is None\n assert ud.a == d['a']\n assert ud.a.b == 'a->b'\n\n\nDict-Style Access and Hierarchical Keys\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nBecause a `udict` is a `dict`, you can of course access it like a `dict`:\n\n.. code-block:: python\n\n ud = udict({'foo': 1})\n assert 'foo' in ud\n ud['foo'] = 2\n ud['foo'] += 1\n assert ud.get('bar', 42) == 42\n del ud['foo']\n\nWhen a `udict` instance contains nested `udict` instances, you can do the\nnormal `dict` operations with dotted keys that traverse multiple levels\nof the hierarchical structure:\n\n.. code-block:: python\n\n ud = udict.fromdict({\n 'result': {\n 'status': {\n 'code': 200,\n 'reason': 'OK'\n }\n }\n })\n\n assert ud['result.status.reason'] == 'OK'\n\n # ud['result.status.reason'] would raise a `KeyError` if the `result` had\n # no `status` or the `status` weren't a `dict`.\n # use `get` if you're unsure of existence:\n assert ud.get('result.foo.bar') is None\n assert ud.get('result.foo.bar', 42) == 42\n\n # dotted keys work as expected for other dict-style operations too:\n ud['result.status.code'] = 400\n assert 'result.status' in ud and 'result.status.reason' in ud\n del ud['result.status.code']\n\n\ndict-compatible\n~~~~~~~~~~~~~~~\n\nSince a `udict` is a `dict`, it behaves like a `dict` even when used with\nbrittle code that requires a `dict` instance rather than something that\n\"quacks\" like a `dict`. For example, the stdlib's pretty printing module,\n`pprint`, generates a pretty, indented representation of a `udict` that is\nidentical to the one it generates for a plain `dict`, but `pprint` doesn't\nuse the dict-style representation for non-dicts even if they support all\nthe `dict` methods and register themselves as a `collections.Mapping`.\n\nThe `__init__` method signature matches that of the stdlib's `dict`, so it can\nbe used as a drop-in replacement for `dict` with no code-changes needed apart\nfrom using `udict` instead of `dict` (assuming a suitable `import`).\n\nThe `str` and `repr` are identical as for a plain `dict` also, and a `udict`\nis `==` to an \"equivalent\" `dict`\n\n\nNotes\n-----\n\nAvoiding Ambiguity of Dotted Keys\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nConsider the following `udict`:\n\n.. code-block:: python\n\n ud = udict.fromdict({\n 'a': {\n 'b': 'a->b'\n },\n 'a.b': 'a.b'\n })\n\nWhen doing `ud['a.b']`, you might reasonably expect that to evaluate to\n`'a.b'`, because there is a top-level `'a.b'` key. But it would\nalso be reasonable to expect `ud['a.b']` to evaluate to `'a->b'`, since\na dotted key is interpreted as a key that traverses a path from the base `udict`\nthrough a sequence of one more child `dict` values, as described above.\n\nIn order to avoid such ambiguities, dict-style access like `ud['a.b']` or\n`ud.get('a.b')` is *always* interpreted as if it were `ud['a']['b']` or\n`ud.get('a', {}).get('b')`, respectively. That means you could never access the\ntop-level `'a.b'` in the `udict` above using dict-style access. You'll either\nget the value of a nested `udict`, get a `KeyError` (or default value in\ncase of `udict.get`), or get a `TypeError` in some cases (following normal\nPython dict behavior). To access the top-level `'a.b'` mapping,\nuse `getattr(ud, 'a.b')` instead. The attribute-style accessors (`hasattr`,\n`getattr`, `setattr`, and `delattr`) *always* interpret a key literally, with\nno special treatment of keys that contain dots.\n\nThus, the simple rule to remember is::\n\n dict-style access with a dotted key is *always* interpreted hierarchically,\n and attribute-style access is *always* interpreted non-hierarchically.\n\n\nReasoning about udict Operations\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe following table shows how accessing a value on a `udict` corresponds\nto one or more operations on a plain `dict` that yield the same result.\n\n.. table::\n\n ======================= =============================\n udict operation dict operation(s)\n ======================= =============================\n ud['a'] d['a']\n ud.get('a') d.get('a')\n ud.get('a', 42) d.get('a', 42)\n ud.a d['a']\n getattr(ud, 'a') d['a']\n getattr(ud, 'a', 42) d.get('a', 42)\n ud['a.b'] d['a']['b']\n ud.get('a.b') d.get('a', {}).get('b')\n ud.get('a.b', 42) d.get('a', {}).get('b', 42)\n getattr(ud, 'a.b') d['a.b']\n getattr(ud, 'a.b', 42) d.get('a.b', 42)\n ud.a.b d['a']['b']\n ======================= =============================\n\n\nThe only significant difference between operations on the left-side and those\non the right-side above is when an exception is raised due to there being no\nsuitable mapping (and no default as there might be with `get` and `getattr`).\nIn such cases, attribute-style access on a `udict` yields an `AttributeError`\n(matching standard Python behavior for attribute access), whereas the\nequivalent operation on a `dict` would yield a `KeyError`.\n\n\nChanges\n=======\n\nVersion 0.4.3 (2017-07-23)\n--------------------------\n\n * doc changes to get description formatted correctly on both github and pypi\n\n\nVersion 0.4.0 (2017-07-23)\n--------------------------\n\n * support python 2.7 and 3.4+, as well as pypy (pypy2 and dev 3.5 pypy)\n * 100% test coverage\n * making available on pypi\n\n\nVersion 0.3.0 (2014-08-09)\n--------------------------\n\n * added support for `dir` method to improve interactive use (exposes stored keys as well as the normal instance and class attributes that would be expected)\n * updates to ensure that `__missing__` is only used from `__getitem__`, and never from methods like `get` or by inadvertently using `__getitem__` from another method\n * more tests\n\n\nVersion 0.2.0 (2014-07-27)\n--------------------------\n\n * main class is now 'uberdict.udict' (was 'uberdict.UberDict')\n * changes to how dotted keys are handled (dots have no special meaning for 'getattr', 'setattr', 'hasattr', 'delattr' but do for 'get' and '__getitem__' and friends)\n * improved README docs and examples\n * more tests\n\n\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://github.com/eukaryote/uberdict/", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "uberdict", "package_url": "https://pypi.org/project/uberdict/", "platform": "any", "project_url": "https://pypi.org/project/uberdict/", "project_urls": { "Homepage": "http://github.com/eukaryote/uberdict/" }, "release_url": "https://pypi.org/project/uberdict/0.4.3/", "requires_dist": [ "check-manifest; extra == 'dev'", "wheel; extra == 'dev'", "pytest; extra == 'test'", "pytest-pep8; extra == 'test'" ], "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4", "summary": "A Python dict that supports attribute-style access as well as hierarchical keys.", "version": "0.4.3" }, "last_serial": 3043676, "releases": { "0.4.0": [ { "comment_text": "", "digests": { "md5": "b66eadd2c25fcb5b6fe1fdacabdf62c6", "sha256": "71095fd953ea7d7ee67149c62003d7355108b03daa3e555771b746616d2f0cf3" }, "downloads": -1, "filename": "uberdict-0.4.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "b66eadd2c25fcb5b6fe1fdacabdf62c6", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4", "size": 11762, "upload_time": "2017-07-23T21:02:12", "url": "https://files.pythonhosted.org/packages/d3/c6/51c2cd3900c6b4ee9863e799a10e5176d469e595afe933b4c31294c9be99/uberdict-0.4.0-py2.py3-none-any.whl" } ], "0.4.1": [ { "comment_text": "", "digests": { "md5": "adc09193e924d4bca9f5f561071c4b61", "sha256": "064fb31e80dde9cd57a140df83b70d9fce2d5a7516e3e468d7a7618a7c478dec" }, "downloads": -1, "filename": "uberdict-0.4.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "adc09193e924d4bca9f5f561071c4b61", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4", "size": 6582, "upload_time": "2017-07-23T21:46:30", "url": "https://files.pythonhosted.org/packages/94/88/4d59246d3eb2e691c3ddf6d6637628ada28e421613f90f13e875b9cce47f/uberdict-0.4.1-py2.py3-none-any.whl" } ], "0.4.2": [ { "comment_text": "", "digests": { "md5": "406e2f6e7b7c9f48ada9121dfcf8c2d6", "sha256": "37f1982f3f26780290948564a902fe7f1ebc6763f3d90ade92482b2492a34613" }, "downloads": -1, "filename": "uberdict-0.4.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "406e2f6e7b7c9f48ada9121dfcf8c2d6", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4", "size": 12024, "upload_time": "2017-07-23T21:50:00", "url": "https://files.pythonhosted.org/packages/bf/ac/ad8173fafefbdb101caca79f62a57cffc72e7ae6ef3bbdebc698012b014c/uberdict-0.4.2-py2.py3-none-any.whl" } ], "0.4.3": [ { "comment_text": "", "digests": { "md5": "212f4be50725aa6b4408e83a3a365ad7", "sha256": "ffaa3e39e41f0bcc8c97302ba858d79f175fb02510b07085226f2982f13eae94" }, "downloads": -1, "filename": "uberdict-0.4.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "212f4be50725aa6b4408e83a3a365ad7", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4", "size": 11996, "upload_time": "2017-07-23T21:58:52", "url": "https://files.pythonhosted.org/packages/6b/a0/b8911b1d3e7f5705a8c71fb416def18a920770377c1708a31caf87f64efe/uberdict-0.4.3-py2.py3-none-any.whl" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "212f4be50725aa6b4408e83a3a365ad7", "sha256": "ffaa3e39e41f0bcc8c97302ba858d79f175fb02510b07085226f2982f13eae94" }, "downloads": -1, "filename": "uberdict-0.4.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "212f4be50725aa6b4408e83a3a365ad7", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4", "size": 11996, "upload_time": "2017-07-23T21:58:52", "url": "https://files.pythonhosted.org/packages/6b/a0/b8911b1d3e7f5705a8c71fb416def18a920770377c1708a31caf87f64efe/uberdict-0.4.3-py2.py3-none-any.whl" } ] }