# -*- coding: utf-8 -*-
from distutils.core import setup

packages = \
['hierarchy_utils']

package_data = \
{'': ['*'], 'hierarchy_utils': ['tests/*']}

setup_kwargs = {
    'name': 'hierarchy-utils',
    'version': '0.1.1',
    'description': 'Utilities for working with hierarchical data structures.',
    'long_description': '* Summary\n\nThis is a collection of functions I find I\'ve been writing over and over again.\n\nI find often 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\': [{\'players\': 10, \'pos\': [\'l\', \'r\', \'c\'], \'team\': \'STARS!\'},\n         {\'players\': 90, \'team\': \'preds\'}]}\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:\nassoc_in_hp({"nhl":[{"team": "stars"  , "players": 10, "pol": ["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\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',
    'author': None,
    'author_email': None,
    'url': 'https://github.com/joefromct/py-hierarchy-utils',
    'packages': packages,
    'package_data': package_data,
    'python_requires': '>=3.5,<4.0',
}


setup(**setup_kwargs)
