{"id":20780692,"url":"https://github.com/ad115/python-treet","last_synced_at":"2025-06-21T05:03:05.711Z","repository":{"id":57477031,"uuid":"215483604","full_name":"Ad115/python-treet","owner":"Ad115","description":"Simple, minimal, but powerful tools to handle any kind of hierarchical (tree) structures","archived":false,"fork":false,"pushed_at":"2023-02-27T21:59:44.000Z","size":469,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-30T20:33:03.631Z","etag":null,"topics":["genetic-algorithm","hierarchical-data","library","python","tree-structure"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ad115.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-10-16T07:22:10.000Z","updated_at":"2023-03-24T22:33:58.000Z","dependencies_parsed_at":"2024-11-18T00:31:28.369Z","dependency_job_id":null,"html_url":"https://github.com/Ad115/python-treet","commit_stats":{"total_commits":27,"total_committers":2,"mean_commits":13.5,"dds":0.03703703703703709,"last_synced_commit":"e328cd1c6fec40fe8fefb985378bbdf00b81efed"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ad115%2Fpython-treet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ad115%2Fpython-treet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ad115%2Fpython-treet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ad115%2Fpython-treet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ad115","download_url":"https://codeload.github.com/Ad115/python-treet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251777808,"owners_count":21642230,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["genetic-algorithm","hierarchical-data","library","python","tree-structure"],"created_at":"2024-11-17T13:38:53.401Z","updated_at":"2025-04-30T20:33:59.264Z","avatar_url":"https://github.com/Ad115.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"Generic tree utilities for Python\n=================================\n\nTrees are one of the most ubiquitous data structures.\n\nThis module defines generic tree-traverse and tree-reduce algorithms that can be\nused with any tree-like object such as filesystem paths, lists, nested \ndictionaries an expression tree or even specialized tree classes! The only thing \nthat must be provided is a function to get child nodes from a parent node.\n\nAlso, trees are usually represented in some fields (such as bioinformatics) in \nthe newick format, which is nontrivial to parse, so this module includes a \nfunction to do this.\n\n\nUsage and examples\n------------------\n\nInstall from [PyPi](https://pypi.org/project/treet/):\n\n```\npip install treet\n```\n\nImport the basic functions, `traverse`, `reduce` and `parse_newick`:\n\n```python\n\nimport treet\n```\n\n###  Use with any kind of structured tree!\n\nAny kind of structured data is supported, in this case, nested dictionaries:\n\n```python\n\ntree = {\n    'label':'A', 'children':[\n        {'label':'B', 'children':[]},\n        {'label':'C', 'children': [\n            {'label':'D', 'children':[]}, \n            {'label':'E', 'children':[]}\n        ]}\n    ]\n}\n\ndef children(node):\n    return node['children']\n\n[node['label'] \n    for node in treet.traverse(tree, children, mode='inorder')]\n\n# Output --\u003e ['B, 'A', 'D', 'C', 'E']\n\ndef as_list(node, children):\n    if not children:\n        return node['label']\n    else:\n        return children\n\ntreet.reduce(tree, children, reduce_fn=as_list)\n\n# Output --\u003e ['B, ['D', 'E']]\n```\n\n###  Even with user-defined classes!\n\nDump a tree in a specialized class format to a string in the newick format.\n\n```python\n\nclass Tree:\n    def __init__(self, label, children=None):\n        self.label = label\n        self.children = children if children else []\n    \n    def is_leaf(self):\n        return len(self.children) == 0\n\ntree = Tree('A', [\n        Tree('B'),\n        Tree('C',[Tree('D'),Tree('E')])\n    ]\n)\n\ndef get_children(node):\n    return node.children\n\ndef node_to_newick(node, children):\n    if node.is_leaf():\n        return node.label\n    else:\n        return f\"({','.join(children)})\"\n\n\ntreet.reduce(tree, get_children, node_to_newick)\n\n# Output --\u003e '(B,(D,E))'\n```\n\n### Compose to perform complex algorithms\n\nGet the subtree induced by a subset of the leaves:\n\n```python\n\ntree = (('A',('B',('C','D'))),'E')\n\ndef is_leaf(node): \n    return isinstance(node, str)\n\ndef get_children(node):\n    return node if not is_leaf(node) else []\n\ndef induced_subtree(leafs):\n    def induced_subtree_generator(node, children):\n        if children:\n            return tuple(ch for ch in children if not ch is None)\n        else:\n            return node if node in leafs else None\n    return induced_subtree_generator\n\nleafs = ['B', 'D', 'E']\ninduced = treet.reduce(tree, get_children, induced_subtree(leafs))\nprint(induced)\n\n# Output --\u003e ((('B',('D',)),),'E')\n\n\ndef merge_unary_nodes(node, children):\n    if is_leaf(node):\n        return node\n    \n    new_children = [\n        ch[0] if (len(ch) == 1) else ch\n        for ch in children\n    ]\n    return tuple(new_children)\n\ntreet.reduce(induced, get_children, merge_unary_nodes)\n\n# Output --\u003e (('B','D'),'E')\n```\n\n### Use even with filesystem paths!\n\nTraverse the `/usr` directory in breadth-first order:\n\n```python\nfrom pathlib import Path\n\ndef enter_folder(path):\n    path = Path(path)\n    return list(path.iterdir()) if path.is_dir() else []\n\nfor item in treet.traverse('/usr', enter_folder, mode='breadth_first'):\n    print(item)\n\n# Output --\u003e\n# /\n# /proc\n# /usr\n# ...\n# /usr/share\n# /usr/bin\n# /usr/sbin\n# ...\n# /usr/bin/jinfo\n# /usr/bin/m2400w\n# ...\n```\n\n\n### Parse a newick-formatted tree structure\n\nAssemble the Newick string to a custom data format:\n\n```python\n\ndef parse_node_data(data_string):\n    '''\n    Example: \n      'data1=xx,data2=yy' \n        -\u003e {'data1':'xx', 'data2': 'yy'}\n    '''\n    items = data_string.split(',')\n    key_value_pairs = (item.split('=') for item in items)\n    return dict(key_value_pairs)\n\ndef parse_branch_length(length_str):\n    return float(length_str) if length_str else 0.0\n\ndef tree_builder(label, children, branch_length, node_data):\n    return {\n        'label': label,\n        'length': branch_length,\n        'data': node_data,\n        'children': children}\n\nnewick = \"(A:0.2[dat=23,other=45], B:12.4[dat=122,other=xyz])root[x=y];\"\n\ntreet.parse_newick(\n    newick,\n    aggregator=tree_builder,\n    feature_parser=parse_node_data,\n    distance_parser=parse_branch_length\n)\n\n# Output -\u003e\n{'label': 'root', 'length':0.0, 'data': {'x':'y'},\n 'children': [\n    {'label': 'A', 'length':0.2, 'data':{'dat':'23','other':'45'}, \n     'children': []},\n    {'label': 'B', 'length':12.4, 'data':{'dat':'122','other':'xyz'},\n     'children': []}, \n]}\n```\n\n\nMeta\n----\n\n**Author**: [Ad115](https://agargar.wordpress.com/) - \n    [Github](https://github.com/Ad115/) – a.garcia230395@gmail.com\n\nDistributed under the MIT license. See [LICENSE](https://github.com/Ad115/treet/blob/master/LICENSE) more information.\n\n\nContributing\n------------\nTo run tests: `pytest treet/* --hypothesis-show-statistics --verbose`\n\nTo run static type check: `mypy treet/*.py`\n\nTo run coverage analysis: `coverage run --source=. -m pytest treet/* --hypothesis-show-statistics --verbose`\n\n1. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug.\n2. Fork [the repository](https://github.com/Ad115/treet/) on GitHub to start making your changes to a feature branch, derived from the **master** branch.\n3. Write a test which shows that the bug was fixed or that the feature works as expected.\n4. Send a pull request and bug the maintainer until it gets merged and published.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fad115%2Fpython-treet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fad115%2Fpython-treet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fad115%2Fpython-treet/lists"}