{ "info": { "author": "Alan Elkner", "author_email": "aelkner@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "# traversify\n\nHandy python classes for manipulating json data, providing syntactic sugar for less verbose, easier to write code.\n\nTraverser class allows one to:\n\n* traverse complex trees of data with dotted syntax rather than the verbose dictionary dereferencing.\n* treat nodes on the tree as lists even if they are singleton dictionaries, eliminating a lot of type-checking code.\n* add or delete branches of the tree with simple dotted syntax.\n* treat missing keys on the tree as None rather than throwing a key exception, much as JavaScript returns undefined.\n* linkage to Filter class (defined next) for powerful tree comparisons or tree pruning.\n\nFilter class allows one to:\n\n* define a set of criteria for comparing two partially incongruous trees by limiting the sets of fields compared.\n* apply said criteria to prune a tree of any unwanted fields.\n\n# Traverser\n\nPass tree data to Traverser, either as a list, dictionary, json string or any class offering a json method, and the resultant object will provide the syntactic sugar for traversing with dotted syntax, treating singleston nodes as lists:\n\n```pycon\n>>> from traversify import Traverser\n>>> obj = Traverser({'id': 1, 'username': 'jdoe'})\n>>> obj.id\n1\n>>> obj.username\n'jdoe'\n>>> obj.bad_key is None\nTrue\n>>> [node.id for node in obj]\n[1]\n>>> obj[0].id\n1\n>>> {'id': 1, 'username': 'jdoe'} in obj\nTrue\n```\n\nNot only can singletons be addressed as lists, but append and extend methods are available to turn singletons into lists on the fly:\n\n```pycon\n>>> obj = Traverser({'id': 1})\n>>> obj.append({'id': 2})\n>>> obj.extend([{'id': 3, 'id': 4}])\n>>> [node.id for node in obj]\n[1, 2, 3, 4]\n```\n\nAt any time, a Traverser instance will return the underlying value when called:\n\n```pycon\n>>> obj = Traverser({'id': 1})\n>>> obj()\n{'id': 1}\n```\n\nThe tree can be updated using dotted syntax. Note that by default, a Traverser instance makes a deepcopy of the json data so that there are no unintended side effects:\n\n```pycon\n>>> data = {'id': 1, 'username': 'jdoe'}\n>>> obj = Traverser(data)\n>>> obj.id = 2\n>>> del obj.username\n>>> obj()\n{'id': 2}\n>>> data\n{'id': 1, 'username': 'jdoe'}\n```\n\nHowever, if the side-effect of updating the data passed is desired (perhaps due to memory constaints), then pass deepcopy=False:\n\n```pycon\n>>> data = {'id': 1}\n>>> obj = Traverser(data, deepcopy=False)\n>>> obj.id = 2\n>>> obj()\n{'id': 2}\n>>> data\n{'id': 2}\n```\n\nIn case there are keys that are not identifiers, then dictionary dereferencing can still be used:\n\n```pycon\n>>> obj = Traverser({'@xsi.type': 'textarea'})\n>>> obj['@xsi.type']\n'textarea'\n```\n\nThe get method allows traversing multiple levels in one call, using dots to set off the levels:\n```pycon\n>>> obj = Traverser({'root': {'username': 'any'}})\n>>> obj.get('root.username')\n'any'\n```\n\nAlso, the get method supports dot-escaping so that keys containing dots can still be traversed:\n\n```pycon\n>>> obj = Traverser({'@xsi.type': 'textarea'})\n>>> obj.get('@xsi..type')\n'textarea'\n```\n\nThere's a set method that will update a node multiple levels down and even build out branches that aren't already there:\n\n```pycon\n>>> obj = Traverser({'stats': {'id': 1}})\n>>> obj.set('stats.id', 2)\n>>> obj()\n{'stats': {'id': 2}}\n>>> obj.set('users.0.username', 'any')\n>>> obj()\n{'stats': {'id': 2}, 'users': [{'username': 'any'}]}\n```\n\nTo save the trouble of importing json and using dumps, there's a handy to_json method:\n\n```pycon\n>>> obj = Traverser({'id': 1})\n>>> obj.to_json()\n'{\"id\": 1}'\n```\n\n# Filter\n\nOften one needs to compare two trees without taking into account irrelavant fields, like when records in the tree have ids, but a new record doesn't have it yet. Filter provides a way to make this less verbose by providing blacklist and whitelist attributes for controlled comparison:\n\n```pycon\n>>> from traversify import Traverser, Filter\n>>> id_exclude_filter = Filter(blacklist='id')\n>>> record = Traverser({'id': 1, 'username': 'jdoe'})\n>>> id_exclude_filter.are_equal(record, {'username': 'jdoe'})\nTrue\n```\n\nThe same filter can be used to prune a tree of its unwanted fields:\n\n```pycon\n>>> id_exclude_filter.prune(record)\n>>> record()\n{'username': 'jdoe'}\n```\n\nIf a filter is passed while creating a Traverser instance, then `==`, `in` and the `prune()` method will use it to do the comparison or pruning:\n\n```pycon\n>>> record = Traverser({'id': 1, 'username': 'jdoe'}, filter=Filter(blacklist='id'))\n>>> record == {'username': 'jdoe'}\nTrue\n>>> {'username': 'jdoe'} in record\nTrue\n>>> record.prune()\n>>> record()\n{'username': 'jdoe'}\n```\n\nTraverser's prune method will accept a filter to override the default (or supply one not already supplied):\n\n```pycon\n>>> record = Traverser({'id': 1, 'username': 'jdoe'})\n>>> record.prune(filter=Filter(blacklist='id'))\n>>> record()\n{'username': 'jdoe'}\n```\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/aelkner/traversify", "keywords": "", "license": "GNU GENERAL PUBLIC LICENSE version 3", "maintainer": "", "maintainer_email": "", "name": "traversify", "package_url": "https://pypi.org/project/traversify/", "platform": "", "project_url": "https://pypi.org/project/traversify/", "project_urls": { "Homepage": "https://github.com/aelkner/traversify" }, "release_url": "https://pypi.org/project/traversify/1.1.2/", "requires_dist": null, "requires_python": "", "summary": "Handy python classes for manipulating json data, providing syntactic sugar for less verbose, easier to write code.", "version": "1.1.2" }, "last_serial": 5134626, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "44f6aebbc7f926c711b8124c9d524bfb", "sha256": "7a4dc33844f3dd7d1bc1406320e00ca0a16ea084428540b052edd74d5550e3b1" }, "downloads": -1, "filename": "traversify-1.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "44f6aebbc7f926c711b8124c9d524bfb", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 19683, "upload_time": "2018-12-27T19:53:01", "url": "https://files.pythonhosted.org/packages/0f/b7/6fdf1c1965d517ee20b5cefc3b949b80366d65ff6ce5e1a29f949233485a/traversify-1.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3e896856f82b5d7f9f7e10e66b5dbda3", "sha256": "171fb9ee0a470f8fc1d611fb1db7520bee82ff725e746afdcf2420fa4809e75b" }, "downloads": -1, "filename": "traversify-1.0.0.tar.gz", "has_sig": false, "md5_digest": "3e896856f82b5d7f9f7e10e66b5dbda3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6472, "upload_time": "2018-12-27T19:53:03", "url": "https://files.pythonhosted.org/packages/4e/a2/06c68b08fb5c0a5aad7177fc190f08c8b2babe7c009dd815879a3623d0db/traversify-1.0.0.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "ad794d367410888fd23dc0156da4af08", "sha256": "3833d2c446dad81a3c7c0bb471559fa9272e1d634724cc26548a1f182e56ce0e" }, "downloads": -1, "filename": "traversify-1.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "ad794d367410888fd23dc0156da4af08", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20143, "upload_time": "2019-02-14T21:38:09", "url": "https://files.pythonhosted.org/packages/5f/ea/d707e81bd5ac190cdd4c502dd850ac5f6ca8d17ee0762f5e7447c0f52173/traversify-1.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "76db3d4c86aa2176ae2ab2c1af35039e", "sha256": "e4cbf8efe46610f36a20863d5ae60ca7431b246aae863dc255a35a10d0dc115b" }, "downloads": -1, "filename": "traversify-1.1.0.tar.gz", "has_sig": false, "md5_digest": "76db3d4c86aa2176ae2ab2c1af35039e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5278, "upload_time": "2019-02-14T21:38:11", "url": "https://files.pythonhosted.org/packages/42/9d/b9fb7f6921e76a1990c16f7b0294d646dee7683decfe54e5d1ee13b302a6/traversify-1.1.0.tar.gz" } ], "1.1.1": [ { "comment_text": "", "digests": { "md5": "4a53aff0fa1bbc667b4a10e1c1a3abb4", "sha256": "46dfdc05f162e13a07d9cb59aa9c8037718625671535b2dc4893e950b23beeb3" }, "downloads": -1, "filename": "traversify-1.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "4a53aff0fa1bbc667b4a10e1c1a3abb4", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20224, "upload_time": "2019-02-15T18:43:29", "url": "https://files.pythonhosted.org/packages/94/9d/8a53ecea9162a0f7662f651193d7f4ff860f9255fc0291ca38a0b74da3cd/traversify-1.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "cfeba2f6047f4baf1f115941a124043d", "sha256": "3d42ca8c8def63e6e41a5c814e9d4c66192e70c2f009dacdf2f4a5a6206b8ec8" }, "downloads": -1, "filename": "traversify-1.1.1.tar.gz", "has_sig": false, "md5_digest": "cfeba2f6047f4baf1f115941a124043d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5378, "upload_time": "2019-02-15T18:43:30", "url": "https://files.pythonhosted.org/packages/2a/ce/54929d968dfd9b77b4a8a2f97fc8ef31fb27518a757855bff1188507f4a7/traversify-1.1.1.tar.gz" } ], "1.1.2": [ { "comment_text": "", "digests": { "md5": "8cf2987218ec7e2d9235ea6b5fb45600", "sha256": "66955ea198270b499dd6b1f7af49b2baf794572c4b74e228b4e563451f8619f2" }, "downloads": -1, "filename": "traversify-1.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "8cf2987218ec7e2d9235ea6b5fb45600", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20312, "upload_time": "2019-04-12T15:51:06", "url": "https://files.pythonhosted.org/packages/07/67/30c6e6393b8ed82be287a7ad3d99f73c66fc08837faa0309a502ef9afde7/traversify-1.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7f9e17c251719a125781a6768e983f04", "sha256": "d127880c5f8d5a3be0651fcfc655996bede2434b8eedc9a9b7f67710f882e70b" }, "downloads": -1, "filename": "traversify-1.1.2.tar.gz", "has_sig": false, "md5_digest": "7f9e17c251719a125781a6768e983f04", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5474, "upload_time": "2019-04-12T15:51:07", "url": "https://files.pythonhosted.org/packages/2b/1f/c554628d82cf58ee97c4b5a22c91d43bafc4477f78ed933e9736b5810ed9/traversify-1.1.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "8cf2987218ec7e2d9235ea6b5fb45600", "sha256": "66955ea198270b499dd6b1f7af49b2baf794572c4b74e228b4e563451f8619f2" }, "downloads": -1, "filename": "traversify-1.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "8cf2987218ec7e2d9235ea6b5fb45600", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20312, "upload_time": "2019-04-12T15:51:06", "url": "https://files.pythonhosted.org/packages/07/67/30c6e6393b8ed82be287a7ad3d99f73c66fc08837faa0309a502ef9afde7/traversify-1.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7f9e17c251719a125781a6768e983f04", "sha256": "d127880c5f8d5a3be0651fcfc655996bede2434b8eedc9a9b7f67710f882e70b" }, "downloads": -1, "filename": "traversify-1.1.2.tar.gz", "has_sig": false, "md5_digest": "7f9e17c251719a125781a6768e983f04", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5474, "upload_time": "2019-04-12T15:51:07", "url": "https://files.pythonhosted.org/packages/2b/1f/c554628d82cf58ee97c4b5a22c91d43bafc4477f78ed933e9736b5810ed9/traversify-1.1.2.tar.gz" } ] }