{ "info": { "author": "", "author_email": "", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7" ], "description": "* Summary\n\nThis is a collection of functions I find I've been writing over and over again.\n\nOften times I'm working with hierarchical data structures and attempting\nto apply transformations on them to yield a similar-but-different output\nhierarchical data structures.\n\nThere are lots of ways to do this... these are just utilities for reference to\ndo so.\n\nInput could be nested json, xml, etc and there are [[https://github.com/martinblech/xmltodict][various ways]] to get this into\na python dictionary.\n\nThis python dictionary however still retains the complexity of the original\ndocument.\n\nThis module provides some utility functions (in the spirit of =toolz= / =functoolz=)\nthat can be used to grok hierarchies.\n\n* Hierarchy Path Concepts\n\nMany of the functions receiver a /hierarchy path/ (=hp=).\n\nGiven the example data such as:\n\n#+BEGIN_SRC python\nteams = {\"compile-day\": \"monday\",\n \"compile-secret\": \"SECRET!\",\n \"nhl\": [{\"team\": \"stars\" , \"players\": 10, \"pos\": [\"l\", \"r\", \"c\"]},\n {\"team\": \"bruins\" , \"players\": 30 },\n {\"team\": \"preds\" , \"players\": 90 }],\n \"nba\": [{\"team\": \"mavs\" , \"players\": -9, \"details\": [{\"who\": \"bill\", \"pos\": [\"r\", \"c\", \"l\"]},\n {\"who\": \"ted\", \"pos\": [\"d\"]},\n {\"who\": \"fred\"}]},\n {\"team\": \"bucks\" , \"players\": 3 , \"details\": [{\"who\": \"ken\" , \"pos\": [\"c\"]}]}],}\n#+END_SRC\n\nSome /hierarchy paths/ could look like this:\n\n#+BEGIN_SRC python\n/compile-day\n#+END_SRC\n\nOr any of these:\n#+BEGIN_SRC python\n/nhl/0/details/who\n/nba/*/details/*/\n/nba/*/details/*/who\n#+END_SRC\n\nNotice the use of numbers and/or =*= in the Hierarchy Path that acts as a\nindex-of-list identifier or a globing.\n\nThis idea of a hierarchy path wouldn't work with dictionaries that had numeric\nkeys like =0= and/or dictionaries that have keys such 's =*=. This hasn't been\nan issue for me, as most of my dictionaries are generated from xml, and these\nkeys wouldn't be [[https://www.w3schools.com/xml/xml_elements.asp][valid tags in xml]].\n\n\n* Function listing and Samples\n** =get_in_hp=\n\nLike toolz's =get_in= but works with a Hierarchy Path:\n\n#+BEGIN_SRC python\nget_in_hp(\"/compile-day\", teams)\n# Output:\n'monday'\n\nget_in_hp(\"/nba/*/details/*/who\", teams)\n# Output:\n[['bill', 'ted', 'fred'], ['ken']]\n\nget_in_hp('/nhl/0/players' , teams)\n# Output:\n10\n\nget_in_hp('/nba/*/details/*/' , teams)\n# Output:\n[[{'pos': ['r', 'c', 'l'], 'who': 'bill'},\n {'pos': ['d'], 'who': 'ted'},\n {'who': 'fred'}],\n [{'pos': ['c'], 'who': 'ken'}]]\n\n\nget_in_hp('/nba/*/details/*/who' , teams)\n# Output:\n[['bill', 'ted', 'fred'], ['ken']]\n#+END_SRC\n\n** =flatten_recur=\n\nFlattens recursive lists.\n\n#+BEGIN_SRC python\n\nflatten_recur([['bill', 'ted', 'fred'], ['ken']])\n#=> ['bill', 'ted', 'fred', 'ken']\n\nflatten_recur(get_in_hp(\"/nba/*/details/*/who\", teams) )\n#=> =['bill', 'ted', 'fred', 'ken']\n\n#+END_SRC\n\n** =assoc_in_hp=\nLike toolz's =assoc_in= but works with a hierarchy path:\n\n#+BEGIN_SRC python\n# change team 0's name:\nassoc_in_hp({\"nhl\":[{\"team\": \"stars\" , \"players\": 10},\n {\"team\": \"preds\" , \"players\": 90}]},\n \"/nhl/0/team/\",\n \"STARS!\")\n\n# Output:\n{'nhl': [{'team': 'STARS!', 'players': 10},\n {'team': 'preds', 'players': 90}]}\n\n\n# Change team 1's players count:\nassoc_in_hp({\"nhl\":[{\"team\": \"stars\" , \"players\": 10},\n {\"team\": \"preds\" , \"players\": 90}]},\n \"/nhl/1/players\",\n 40)\n\n# Output:\n{'nhl': [{'players': 10, 'team': 'stars'},\n {'players': 40, 'team': 'preds'}]}\n\n# Should work with deeply nested lists too;\n# Change the second position on the first team to \"coach!\"\nassoc_in_hp({\"nhl\":[{\"team\": \"stars\" , \"players\": 10, \"pos\": [\"l\", \"r\", \"c\"]},\n {\"team\": \"preds\" , \"players\": 90}]},\n \"/nhl/0/pos/2\",\n \"coach!\")\n\n# Output:\n{'nhl': [{'players': 10, 'pos': ['l', 'r', 'coach!'], 'team': 'stars'},\n {'players': 90, 'team': 'preds'}]}\n#+END_SRC\n\n** =update_in_hp=\nSimilar to toolz's =update_in=.\n\nUpdates an input dictionaries value with the result of calling a function on\nthat value.\n\n#+BEGIN_SRC python\n\nmy_fn = lambda x: x + 1\n\nupdate_in_hp({\"nhl\":[{\"team\": \"stars\" , \"players\": 10},\n {\"team\": \"preds\" , \"players\": 90}]},\n \"/nhl/0/players/\",\n my_fn, default=0)\n\n{\"nhl\":[{\"team\": \"stars\" , \"players\": 11},\n {\"team\": \"preds\" , \"players\": 90}]},\n#+END_SRC\n\nIt can gets interesting (hopefully useful?) with wildcards.\n\nLets pretend that we want to apply a 10% raise to all players across the board,\non all teams.\n\n\nThis would be our function:\n\n#+BEGIN_SRC python\ndef ten_percent_raise(salary):\n if salary:\n return salary * 1.10\n else:\n # If they don't have a salary then lets pretend they own us money.\n return -40\n#+END_SRC\n\nThen just apply that function to the correct path for the input dictionary:\n#+BEGIN_SRC python\nupdate_in_hp({\"payroll\": [{\"team\": \"stars\", \"players\": [{\"player\": \"bill\" , \"salary\": 10, },\n {\"player\": \"ted\" , \"salary\": 30, },\n {\"player\": \"ned\" , \"salary\": 20, },\n {\"player\": \"fred\" , },]},\n {\"team\": \"preds\", \"players\": [{\"player\": \"ken\" , \"salary\": 5, },\n {\"player\": \"jen\" , \"salary\": 8, },\n {\"player\": \"ben\" , \"salary\": 9, },\n {\"player\": \"len\" , },]}]},\n \"/payroll/*/players/*/salary\", # path is payroll for all teams, all players, salary node.\n ten_percent_raise)\n\n\n\n{'payroll': [{'players': [{'player': 'bill', 'salary': 11.0},\n {'player': 'ted', 'salary': 33.0},\n {'player': 'ned', 'salary': 22.0},\n {'player': 'fred', 'salary': -40}],\n 'team': 'stars'},\n {'players': [{'player': 'ken', 'salary': 5.5},\n {'player': 'jen', 'salary': 8.8},\n {'player': 'ben', 'salary': 9.9},\n {'player': 'len', 'salary': -40}],\n 'team': 'preds'}]}\n\n#+END_SRC\n\nHere's another (similar) example; Lets b64 encode all the players ssn's:\n\n#+BEGIN_SRC python\nimport base64\n\ndef make_data_not_super_secure(ssn):\n return base64.b64encode(ssn.encode()).decode(\"utf-8\")\n\n\nupdate_in_hp({\"payroll\": [{\"team\": \"stars\", \"players\": [{\"player\": \"bill\" , \"salary\": 10, \"ssn\": \"001-01-0001\"},\n {\"player\": \"ted\" , \"salary\": 30, \"ssn\": \"001-01-0002\"},\n {\"player\": \"ned\" , \"salary\": 20, \"ssn\": \"001-01-0003\"},\n {\"player\": \"fred\" , \"ssn\": \"001-01-0004\"},]},\n {\"team\": \"preds\", \"players\": [{\"player\": \"ken\" , \"salary\": 5, \"ssn\": \"001-01-0005\"},\n {\"player\": \"jen\" , \"salary\": 8, \"ssn\": \"001-01-0006\"},\n {\"player\": \"ben\" , \"salary\": 9, \"ssn\": \"001-01-0007\"},\n {\"player\": \"len\" , \"ssn\": \"001-01-0008\"},]}]},\n \"/payroll/*/players/*/ssn\", # path is payroll for all teams, all players, salary node.\n make_data_not_super_secure)\n\n{'payroll': [{'players': [{'player': 'bill', 'salary': 10, 'ssn': 'MDAxLTAxLTAwMDE='},\n {'player': 'ted', 'salary': 30, 'ssn': 'MDAxLTAxLTAwMDI='},\n {'player': 'ned', 'salary': 20, 'ssn': 'MDAxLTAxLTAwMDM='},\n {'player': 'fred', 'ssn': 'MDAxLTAxLTAwMDQ='}],\n 'team': 'stars'},\n {'players': [{'player': 'ken', 'salary': 5, 'ssn': 'MDAxLTAxLTAwMDU='},\n {'player': 'jen', 'salary': 8, 'ssn': 'MDAxLTAxLTAwMDY='},\n {'player': 'ben', 'salary': 9, 'ssn': 'MDAxLTAxLTAwMDc='},\n {'player': 'len', 'ssn': 'MDAxLTAxLTAwMDg='}],\n 'team': 'preds'}]}\n\n\n#+END_SRC\n\n* TODO test results\n- [ ] add this to jenkins/ci\n\n#+BEGIN_SRC bash\ncwd: /Users/me/git-repos/hierarchy_utils/\ncmd: pytest --color=no\n\n==================================================================================================================================================== test session starts =====================================================================================================================================================\nplatform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.9.0 -- /usr/local/opt/python/bin/python3.7\ncachedir: .pytest_cache\nrootdir: /Users/me/git-repos/hierarchy_utils, inifile: pytest.ini\ncollected 10 items\n\ntests/test_hierarchy_utils.py::test_version PASSED\ntests/test_hierarchy_utils.py::test_path_switchers PASSED\ntests/test_hierarchy_utils.py::test_get_in_usage PASSED\ntests/test_hierarchy_utils.py::test_get_in_hp_atomic PASSED\ntests/test_hierarchy_utils.py::test_get_in_hp_integers PASSED\ntests/test_hierarchy_utils.py::test_get_in_hp_stars_single PASSED\ntests/test_hierarchy_utils.py::test_get_in_hp_stars_multiple PASSED\ntests/test_hierarchy_utils.py::test_my_assoc_in_coll PASSED\ntests/test_hierarchy_utils.py::test_my_assoc_in_hp PASSED\ntests/test_hierarchy_utils.py::test_update_in_hp PASSED\n\n================================================================================================================================================= 10 passed in 0.09 seconds ==================================================================================================================================================\n#+END_SRC\n\n* Ideas/References\n\nhttps://stackoverflow.com/questions/7320319/xpath-like-query-for-nested-python-dictionaries\n\nhttps://jmespath.readthedocs.io/en/latest/\n\nProbably could do a lot of this with xlst... or a billion other ways.\n", "description_content_type": "text/plain", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/joefromct/py-hierarchy-utils", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "hierarchy-utils", "package_url": "https://pypi.org/project/hierarchy-utils/", "platform": "", "project_url": "https://pypi.org/project/hierarchy-utils/", "project_urls": { "Homepage": "https://github.com/joefromct/py-hierarchy-utils" }, "release_url": "https://pypi.org/project/hierarchy-utils/0.1.3/", "requires_dist": null, "requires_python": ">=3.5,<4.0", "summary": "Utilities for working with hierarchical data structures.", "version": "0.1.3" }, "last_serial": 5344558, "releases": { "0.1.1": [ { "comment_text": "", "digests": { "md5": "bd0b024b812e73da88ca98bbe0d89674", "sha256": "2c954a11b83146163898fc9daabf0223d20279e5665865d99ae9e6c60297a477" }, "downloads": -1, "filename": "hierarchy_utils-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "bd0b024b812e73da88ca98bbe0d89674", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5,<4.0", "size": 5723, "upload_time": "2019-04-26T02:07:44", "url": "https://files.pythonhosted.org/packages/28/fe/b824a99ad0124cdb26c44c3cd748bf07a933dda1b950a9c4e72f84ec3322/hierarchy_utils-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "48bb3b7361fd3f4e2a5151a54a63835e", "sha256": "b3a1c8d15f8ed16d8b85e7b1fe553e4cc7aea6864464bb1512a0726038402ba1" }, "downloads": -1, "filename": "hierarchy_utils-0.1.1.tar.gz", "has_sig": false, "md5_digest": "48bb3b7361fd3f4e2a5151a54a63835e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5,<4.0", "size": 7098, "upload_time": "2019-04-26T02:07:46", "url": "https://files.pythonhosted.org/packages/f0/dc/395db4894a0b568f8d24b7f9f51cf02f031b8aab2ba34c8d02dd49971fe1/hierarchy_utils-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "b12215e35ad8bd3d4ea84acba03a1a36", "sha256": "c35e3a43158e86a91382f304d599fe543aae798da3efccff387ba2bd29adf7c7" }, "downloads": -1, "filename": "hierarchy_utils-0.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "b12215e35ad8bd3d4ea84acba03a1a36", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5,<4.0", "size": 6928, "upload_time": "2019-05-30T05:07:44", "url": "https://files.pythonhosted.org/packages/2c/94/9e25eb838ee112e9a44d7214954ff43150e7757e120c5501cebc8eb4fa65/hierarchy_utils-0.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "7e805e14512cddf862b68a36b1f4f8dd", "sha256": "43dbf503a7c03aa863ebfbe2363dc4f1328a152053dc1ea8177fa246044999d9" }, "downloads": -1, "filename": "hierarchy_utils-0.1.2.tar.gz", "has_sig": false, "md5_digest": "7e805e14512cddf862b68a36b1f4f8dd", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5,<4.0", "size": 8462, "upload_time": "2019-05-30T05:07:46", "url": "https://files.pythonhosted.org/packages/81/f8/2e66327847131548e7bd0d849caa4af01f20fec14270165699099660cedc/hierarchy_utils-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "52197b6b6af89b9bba75889e6cc8a409", "sha256": "65f4eb89e733c31d71bfe806b8859bef0a7677dacbdc12a728c21de5f5c2e045" }, "downloads": -1, "filename": "hierarchy_utils-0.1.3-py3-none-any.whl", "has_sig": false, "md5_digest": "52197b6b6af89b9bba75889e6cc8a409", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5,<4.0", "size": 6937, "upload_time": "2019-05-31T21:14:19", "url": "https://files.pythonhosted.org/packages/f8/9e/fa9e480464fd14205dc68622fd7511e733d6ecebca76c4b1b82c2304da80/hierarchy_utils-0.1.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a9efe004af47d228de150930713629d3", "sha256": "b84aebdcd3a6669e544188df7aa5b79ff834dd2b99a494510d5abdb9aae70c29" }, "downloads": -1, "filename": "hierarchy_utils-0.1.3.tar.gz", "has_sig": false, "md5_digest": "a9efe004af47d228de150930713629d3", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5,<4.0", "size": 8459, "upload_time": "2019-05-31T21:14:20", "url": "https://files.pythonhosted.org/packages/14/c1/a911c22e26e7aaa38b2e3019e8a6c66db4181f7d794405c9907f7fccfbbf/hierarchy_utils-0.1.3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "52197b6b6af89b9bba75889e6cc8a409", "sha256": "65f4eb89e733c31d71bfe806b8859bef0a7677dacbdc12a728c21de5f5c2e045" }, "downloads": -1, "filename": "hierarchy_utils-0.1.3-py3-none-any.whl", "has_sig": false, "md5_digest": "52197b6b6af89b9bba75889e6cc8a409", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5,<4.0", "size": 6937, "upload_time": "2019-05-31T21:14:19", "url": "https://files.pythonhosted.org/packages/f8/9e/fa9e480464fd14205dc68622fd7511e733d6ecebca76c4b1b82c2304da80/hierarchy_utils-0.1.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a9efe004af47d228de150930713629d3", "sha256": "b84aebdcd3a6669e544188df7aa5b79ff834dd2b99a494510d5abdb9aae70c29" }, "downloads": -1, "filename": "hierarchy_utils-0.1.3.tar.gz", "has_sig": false, "md5_digest": "a9efe004af47d228de150930713629d3", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5,<4.0", "size": 8459, "upload_time": "2019-05-31T21:14:20", "url": "https://files.pythonhosted.org/packages/14/c1/a911c22e26e7aaa38b2e3019e8a6c66db4181f7d794405c9907f7fccfbbf/hierarchy_utils-0.1.3.tar.gz" } ] }