{ "info": { "author": "Anders Huss", "author_email": "andhus@kth.se", "bugtrack_url": null, "classifiers": [], "description": "[![Build Status](https://travis-ci.com/andhus/scantree.svg?branch=master)](https://travis-ci.com/andhus/scantree)\n[![codecov](https://codecov.io/gh/andhus/scantree/branch/master/graph/badge.svg)](https://codecov.io/gh/andhus/scantree)\n# scantree\nRecursive directory iterator supporting:\n- flexible filtering including wildcard path matching\n- in memory representation of file-tree (for repeated access)\n- efficient access to directory entry properties (`posix.DirEntry` interface) extended with real path and path relative to the recursion root directory\n- detection and handling of cyclic symlinks\n\n## Installation\n```commandline\npip install scantree\n```\n\n## Usage\nSee source code for full documentation, some generic examples below.\n\nGet matching file paths:\n```python\nfrom scantree import scantree, RecursionFilter\n\ntree = scantree('/path/to/dir', RecursionFilter(match=['*.txt']))\nprint([path.relative for path in tree.filepaths()])\nprint([path.real for path in tree.filepaths()])\n```\n```\n['d1/d2/file3.txt', 'd1/file2.txt', 'file1.txt'] \n['/path/to/other_dir/file3.txt', '/path/to/dir/d1/file2.txt', '/path/to/dir/file1.txt'] \n```\n\nAccess metadata of directory entries in file tree:\n```python\nd2 = tree.directories[0].directories[0]\nprint(type(d2))\nprint(d2.path.absolute)\nprint(d2.path.real)\nprint(d2.path.is_symlink())\nprint(d2.files[0].relative)\n```\n```\nscantree._node.DirNode\n/path/to/dir/d1/d2\n/path/to/other_dir\nTrue\nd1/d2/file3.txt\n```\n\nAggregate information by operating on tree:\n```python\nhello_count = tree.apply(\n file_apply=lambda path: sum([\n w.lower() == 'hello' for w in\n path.as_pathlib().read_text().split()\n ]),\n dir_apply=lambda dir_: sum(dir_.entries),\n)\nprint(hello_count)\n```\n```\n3\n```\n\n```python\nhello_count_tree = tree.apply(\n file_apply=lambda path: {\n 'name': path.name,\n 'count': sum([\n w.lower() == 'hello'\n for w in path.as_pathlib().read_text().split()\n ])\n },\n dir_apply=lambda dir_: {\n 'name': dir_.path.name,\n 'count': sum(e['count'] for e in dir_.entries),\n 'sub_counts': [e for e in dir_.entries]\n },\n)\nfrom pprint import pprint\npprint(hello_count_tree)\n```\n```\n{'count': 3,\n 'name': 'dir',\n 'sub_counts': [{'count': 2, 'name': 'file1.txt'},\n {'count': 1,\n 'name': 'd1',\n 'sub_counts': [{'count': 1, 'name': 'file2.txt'},\n {'count': 0,\n 'name': 'd2',\n 'sub_counts': [{'count': 0,\n 'name': 'file3.txt'}]}]}]}\n```\n\nFlexible filtering:\n```python\nwithout_hidden_files = scantree('.', RecursionFilter(match=['*', '!.*']))\n\nwithout_palindrome_linked_dirs = scantree(\n '.',\n lambda paths: [\n p for p in paths if not (\n p.is_dir() and \n p.is_symlink() and \n p.name == p.name[::-1]\n )\n ]\n)\n```\n\nComparison:\n```python\ntree = scandir('path/to/dir')\n# make some operations on filesystem, make sure file tree is the same:\nassert tree == scandir('path/to/dir')\n\n# tree contains absolute/real path info:\nimport shutil\nshutil.copytree('path/to/dir', 'path/to/other_dir') \nnew_tree = scandir('path/to/other_dir')\nassert tree != new_tree\nassert (\n [p.relative for p in tree.leafpaths()] == \n [p.relative for p in new_tree.leafpaths()]\n)\n```\n\nInspect symlinks:\n```python\nfrom scantree import CyclicLinkedDir\n\nfile_links = []\ndir_links = []\ncyclic_links = []\n\ndef file_apply(path):\n if path.is_symlink():\n file_links.append(path)\n\ndef dir_apply(dir_node):\n if dir_node.path.is_symlink():\n dir_links.append(dir_node.path)\n if isinstance(dir_node, CyclicLinkedDir):\n cyclic_links.append((dir_node.path, dir_node.target_path))\n\nscantree('.', file_apply=file_apply, dir_apply=dir_apply)\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/andhus/scantree", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "scantree", "package_url": "https://pypi.org/project/scantree/", "platform": "", "project_url": "https://pypi.org/project/scantree/", "project_urls": { "Homepage": "https://github.com/andhus/scantree" }, "release_url": "https://pypi.org/project/scantree/0.0.1/", "requires_dist": null, "requires_python": "", "summary": "Flexible recursive directory iterator: scandir meets glob(\"**\", recursive=True)", "version": "0.0.1" }, "last_serial": 5006469, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "e7b37d7292c0d4edc96246e8d681b2b5", "sha256": "2a8b163de0e4b2f9e4f37f8caf3f0b265172bbf174111e1bebc7955581895b39" }, "downloads": -1, "filename": "scantree-0.0.1.tar.gz", "has_sig": false, "md5_digest": "e7b37d7292c0d4edc96246e8d681b2b5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13449, "upload_time": "2019-03-30T08:56:45", "url": "https://files.pythonhosted.org/packages/35/0a/8709b1516110e7b5e1ef796426d8e3fcdb96d83a0cc2639a3d559df1b7c7/scantree-0.0.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "e7b37d7292c0d4edc96246e8d681b2b5", "sha256": "2a8b163de0e4b2f9e4f37f8caf3f0b265172bbf174111e1bebc7955581895b39" }, "downloads": -1, "filename": "scantree-0.0.1.tar.gz", "has_sig": false, "md5_digest": "e7b37d7292c0d4edc96246e8d681b2b5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13449, "upload_time": "2019-03-30T08:56:45", "url": "https://files.pythonhosted.org/packages/35/0a/8709b1516110e7b5e1ef796426d8e3fcdb96d83a0cc2639a3d559df1b7c7/scantree-0.0.1.tar.gz" } ] }