Directory Tree Generator source code

上级 e3643d40
# RP Tree
RP Tree is a command-line tool to generate a directory tree diagram.
## Run the App
To run **RP Tree**, you need to download the source code. Then open a terminal or command-line window and run the following steps:
1. Create and activate a Python virtual environment
```sh
$ cd rptree/
$ python -m venv ./venv
$ source venv/bin/activate
(venv) $
```
2. Run the application
```sh
(venv) $ python tree.py /path/to/directory/
```
**Note:** The `-h` or `--help` option provides help on how to use RP Tree.
## Current Features
If you run RP Tree with a directory path as an argument, then you get the full directory tree printed on your screen. The default input directory is your current directory.
RP Tree also provides the following options:
- `-v`, `--version` shows the application version and exits
- `-h`, `--help` show a usage message
- `-d`, `--dir-only` generates a directory-only tree
- `-o`, `--output-file` generates a tree and save it to a file in markdown format
## Release History
- 0.1.0
- A work in progress
## About the Author
Leodanis Pozo Ramos - Email: leodanis@realpython.com
"""Top-level package for RP Tree."""
__version__ = "0.1.0"
"""This module provides the RP Tree CLI."""
import argparse
import pathlib
import sys
from . import __version__
from .rptree import DirectoryTree
def main():
args = parse_cmd_line_arguments()
root_dir = pathlib.Path(args.root_dir)
if not root_dir.is_dir():
print("The specified root directory doesn't exist")
sys.exit()
tree = DirectoryTree(
root_dir, dir_only=args.dir_only, output_file=args.output_file
)
tree.generate()
def parse_cmd_line_arguments():
parser = argparse.ArgumentParser(
prog="tree",
description="RP Tree, a directory tree generator",
epilog="Thanks for using RP Tree!",
)
parser.version = f"RP Tree v{__version__}"
parser.add_argument("-v", "--version", action="version")
parser.add_argument(
"root_dir",
metavar="ROOT_DIR",
nargs="?",
default=".",
help="Generate a full directory tree starting at ROOT_DIR",
)
parser.add_argument(
"-d",
"--dir-only",
action="store_true",
help="Generate a directory-only tree",
)
parser.add_argument(
"-o",
"--output-file",
metavar="OUTPUT_FILE",
nargs="?",
default=sys.stdout,
help="Generate a full directory tree and save it to a file",
)
return parser.parse_args()
"""This module provides RP Tree main module."""
import os
import pathlib
import sys
PIPE = "│"
ELBOW = "└──"
TEE = "├──"
PIPE_PREFIX = "│ "
SPACE_PREFIX = " "
class DirectoryTree:
def __init__(self, root_dir, dir_only=False, output_file=sys.stdout):
self._output_file = output_file
self._generator = _TreeGenerator(root_dir, dir_only)
def generate(self):
tree = self._generator.build_tree()
if self._output_file != sys.stdout:
# Wrap the tree in a markdown code block
tree.insert(0, "```")
tree.append("```")
self._output_file = open(
self._output_file, mode="w", encoding="UTF-8"
)
with self._output_file as stream:
for entry in tree:
print(entry, file=stream)
class _TreeGenerator:
def __init__(self, root_dir, dir_only=False):
self._root_dir = pathlib.Path(root_dir)
self._dir_only = dir_only
self._tree = []
def build_tree(self):
self._tree_head()
self._tree_tail(self._root_dir)
return self._tree
def _tree_head(self):
self._tree.append(f"{self._root_dir}{os.sep}")
self._tree.append(PIPE)
def _tree_tail(self, directory, prefix=""):
entries = self._prepare_entries(directory)
entries_count = len(entries)
for index, entry in enumerate(entries):
connector = ELBOW if index == entries_count - 1 else TEE
if entry.is_dir():
self._add_directory(
entry, index, entries_count, prefix, connector
)
else:
self._add_file(entry, prefix, connector)
def _prepare_entries(self, directory):
entries = directory.iterdir()
if self._dir_only:
entries = [entry for entry in entries if entry.is_dir()]
return entries
entries = sorted(entries, key=lambda entry: entry.is_file())
return entries
def _add_directory(
self, directory, index, entries_count, prefix, connector
):
self._tree.append(f"{prefix}{connector} {directory.name}{os.sep}")
if index != entries_count - 1:
prefix += PIPE_PREFIX
else:
prefix += SPACE_PREFIX
self._tree_tail(
directory=directory,
prefix=prefix,
)
self._tree.append(prefix.rstrip())
def _add_file(self, file, prefix, connector):
self._tree.append(f"{prefix}{connector} {file.name}")
#!/usr/bin/env python3
"""This module provides RP Tree entry point script."""
from rptree.cli import main
if __name__ == "__main__":
main()
"""Top-level package for RP Tree."""
__version__ = "0.1.0"
"""Top-level package for RP Tree."""
__version__ = "0.1.0"
"""This module provides RP Tree main module."""
import os
import pathlib
PIPE = "│"
ELBOW = "└──"
TEE = "├──"
PIPE_PREFIX = "│ "
SPACE_PREFIX = " "
class DirectoryTree:
def __init__(self, root_dir):
self._generator = _TreeGenerator(root_dir)
def generate(self):
tree = self._generator.build_tree()
for entry in tree:
print(entry)
class _TreeGenerator:
def __init__(self, root_dir):
self._root_dir = pathlib.Path(root_dir)
self._tree = []
def build_tree(self):
self._tree_head()
self._tree_tail(self._root_dir)
return self._tree
def _tree_head(self):
self._tree.append(f"{self._root_dir}{os.sep}")
self._tree.append(PIPE)
def _tree_tail(self, directory, prefix=""):
entries = directory.iterdir()
entries = sorted(entries, key=lambda entry: entry.is_file())
entries_count = len(entries)
for index, entry in enumerate(entries):
connector = ELBOW if index == entries_count - 1 else TEE
if entry.is_dir():
self._add_directory(
entry, index, entries_count, prefix, connector
)
else:
self._add_file(entry, prefix, connector)
def _add_directory(
self, directory, index, entries_count, prefix, connector
):
self._tree.append(f"{prefix}{connector} {directory.name}{os.sep}")
if index != entries_count - 1:
prefix += PIPE_PREFIX
else:
prefix += SPACE_PREFIX
self._tree_tail(
directory=directory,
prefix=prefix,
)
self._tree.append(prefix.rstrip())
def _add_file(self, file, prefix, connector):
self._tree.append(f"{prefix}{connector} {file.name}")
"""Top-level package for RP Tree."""
__version__ = "0.1.0"
"""This module provides the RP Tree CLI."""
import argparse
import pathlib
import sys
from . import __version__
from .rptree import DirectoryTree
def main():
args = parse_cmd_line_arguments()
root_dir = pathlib.Path(args.root_dir)
if not root_dir.is_dir():
print("The specified root directory doesn't exist")
sys.exit()
tree = DirectoryTree(root_dir)
tree.generate()
def parse_cmd_line_arguments():
parser = argparse.ArgumentParser(
prog="tree",
description="RP Tree, a directory tree generator",
epilog="Thanks for using RP Tree!",
)
parser.version = f"RP Tree v{__version__}"
parser.add_argument("-v", "--version", action="version")
parser.add_argument(
"root_dir",
metavar="ROOT_DIR",
nargs="?",
default=".",
help="Generate a full directory tree starting at ROOT_DIR",
)
return parser.parse_args()
"""This module provides RP Tree main module."""
import os
import pathlib
PIPE = "│"
ELBOW = "└──"
TEE = "├──"
PIPE_PREFIX = "│ "
SPACE_PREFIX = " "
class DirectoryTree:
def __init__(self, root_dir):
self._generator = _TreeGenerator(root_dir)
def generate(self):
tree = self._generator.build_tree()
for entry in tree:
print(entry)
class _TreeGenerator:
def __init__(self, root_dir):
self._root_dir = pathlib.Path(root_dir)
self._tree = []
def build_tree(self):
self._tree_head()
self._tree_tail(self._root_dir)
return self._tree
def _tree_head(self):
self._tree.append(f"{self._root_dir}{os.sep}")
self._tree.append(PIPE)
def _tree_tail(self, directory, prefix=""):
entries = directory.iterdir()
entries = sorted(entries, key=lambda entry: entry.is_file())
entries_count = len(entries)
for index, entry in enumerate(entries):
connector = ELBOW if index == entries_count - 1 else TEE
if entry.is_dir():
self._add_directory(
entry, index, entries_count, prefix, connector
)
else:
self._add_file(entry, prefix, connector)
def _add_directory(
self, directory, index, entries_count, prefix, connector
):
self._tree.append(f"{prefix}{connector} {directory.name}{os.sep}")
if index != entries_count - 1:
prefix += PIPE_PREFIX
else:
prefix += SPACE_PREFIX
self._tree_tail(
directory=directory,
prefix=prefix,
)
self._tree.append(prefix.rstrip())
def _add_file(self, file, prefix, connector):
self._tree.append(f"{prefix}{connector} {file.name}")
#!/usr/bin/env python3
"""This module provides RP Tree entry point script."""
from rptree.cli import main
if __name__ == "__main__":
main()
"""Top-level package for RP Tree."""
__version__ = "0.1.0"
"""This module provides the RP Tree CLI."""
import argparse
import pathlib
import sys
from . import __version__
from .rptree import DirectoryTree
def main():
args = parse_cmd_line_arguments()
root_dir = pathlib.Path(args.root_dir)
if not root_dir.is_dir():
print("The specified root directory doesn't exist")
sys.exit()
tree = DirectoryTree(root_dir, dir_only=args.dir_only)
tree.generate()
def parse_cmd_line_arguments():
parser = argparse.ArgumentParser(
prog="tree",
description="RP Tree, a directory tree generator",
epilog="Thanks for using RP Tree!",
)
parser.version = f"RP Tree v{__version__}"
parser.add_argument("-v", "--version", action="version")
parser.add_argument(
"root_dir",
metavar="ROOT_DIR",
nargs="?",
default=".",
help="Generate a full directory tree starting at ROOT_DIR",
)
parser.add_argument(
"-d",
"--dir-only",
action="store_true",
help="Generate a directory-only tree",
)
return parser.parse_args()
"""This module provides RP Tree main module."""
import os
import pathlib
PIPE = "│"
ELBOW = "└──"
TEE = "├──"
PIPE_PREFIX = "│ "
SPACE_PREFIX = " "
class DirectoryTree:
def __init__(self, root_dir, dir_only=False):
self._generator = _TreeGenerator(root_dir, dir_only)
def generate(self):
tree = self._generator.build_tree()
for entry in tree:
print(entry)
class _TreeGenerator:
def __init__(self, root_dir, dir_only=False):
self._root_dir = pathlib.Path(root_dir)
self._dir_only = dir_only
self._tree = []
def build_tree(self):
self._tree_head()
self._tree_tail(self._root_dir)
return self._tree
def _tree_head(self):
self._tree.append(f"{self._root_dir}{os.sep}")
self._tree.append(PIPE)
def _tree_tail(self, directory, prefix=""):
entries = self._prepare_entries(directory)
entries_count = len(entries)
for index, entry in enumerate(entries):
connector = ELBOW if index == entries_count - 1 else TEE
if entry.is_dir():
self._add_directory(
entry, index, entries_count, prefix, connector
)
else:
self._add_file(entry, prefix, connector)
def _prepare_entries(self, directory):
entries = directory.iterdir()
if self._dir_only:
entries = [entry for entry in entries if entry.is_dir()]
return entries
entries = sorted(entries, key=lambda entry: entry.is_file())
return entries
def _add_directory(
self, directory, index, entries_count, prefix, connector
):
self._tree.append(f"{prefix}{connector} {directory.name}{os.sep}")
if index != entries_count - 1:
prefix += PIPE_PREFIX
else:
prefix += SPACE_PREFIX
self._tree_tail(
directory=directory,
prefix=prefix,
)
self._tree.append(prefix.rstrip())
def _add_file(self, file, prefix, connector):
self._tree.append(f"{prefix}{connector} {file.name}")
#!/usr/bin/env python3
"""This module provides RP Tree entry point script."""
from rptree.cli import main
if __name__ == "__main__":
main()
```
./
├── rptree/
│ ├── __pycache__/
│ │ ├── rptree.cpython-38.pyc
│ │ ├── __init__.cpython-38.pyc
│ │ └── cli.cpython-38.pyc
│ │
│ ├── rptree.py
│ ├── __init__.py
│ └── cli.py
├── .mypy_cache/
│ ├── 3.8/
│ │ ├── os/
│ │ │ ├── path.meta.json
│ │ │ ├── __init__.meta.json
│ │ │ ├── __init__.data.json
│ │ │ └── path.data.json
│ │ │
│ │ ├── importlib/
│ │ │ ├── abc.data.json
│ │ │ ├── __init__.meta.json
│ │ │ ├── abc.meta.json
│ │ │ └── __init__.data.json
│ │ │
│ │ ├── rptree/
│ │ │ ├── cli.data.json
│ │ │ ├── rptree.meta.json
│ │ │ ├── __init__.meta.json
│ │ │ ├── rptree.data.json
│ │ │ ├── __init__.data.json
│ │ │ └── cli.meta.json
│ │ │
│ │ ├── collections/
│ │ │ ├── abc.data.json
│ │ │ ├── __init__.meta.json
│ │ │ ├── abc.meta.json
│ │ │ └── __init__.data.json
│ │ │
│ │ ├── @plugins_snapshot.json
│ │ ├── argparse.data.json
│ │ ├── typing.data.json
│ │ ├── types.data.json
│ │ ├── abc.data.json
│ │ ├── ast.meta.json
│ │ ├── codecs.data.json
│ │ ├── codecs.meta.json
│ │ ├── builtins.data.json
│ │ ├── io.data.json
│ │ ├── ast.data.json
│ │ ├── argparse.meta.json
│ │ ├── builtins.meta.json
│ │ ├── mmap.meta.json
│ │ ├── posix.meta.json
│ │ ├── genericpath.data.json
│ │ ├── _importlib_modulespec.meta.json
│ │ ├── sys.data.json
│ │ ├── abc.meta.json
│ │ ├── mmap.data.json
│ │ ├── _ast.data.json
│ │ ├── typing.meta.json
│ │ ├── pathlib.meta.json
│ │ ├── _ast.meta.json
│ │ ├── io.meta.json
│ │ ├── types.meta.json
│ │ ├── posix.data.json
│ │ ├── sys.meta.json
│ │ ├── genericpath.meta.json
│ │ ├── _importlib_modulespec.data.json
│ │ └── pathlib.data.json
│ │
│ └── .gitignore
├── README.md
└── tree.py
```
"""Top-level package for RP Tree."""
__version__ = "0.1.0"
"""This module provides the RP Tree CLI."""
import argparse
import pathlib
import sys
from . import __version__
from .rptree import DirectoryTree
def main():
args = parse_cmd_line_arguments()
root_dir = pathlib.Path(args.root_dir)
if not root_dir.is_dir():
print("The specified root directory doesn't exist")
sys.exit()
tree = DirectoryTree(
root_dir, dir_only=args.dir_only, output_file=args.output_file
)
tree.generate()
def parse_cmd_line_arguments():
parser = argparse.ArgumentParser(
prog="tree",
description="RP Tree, a directory tree generator",
epilog="Thanks for using RP Tree!",
)
parser.version = f"RP Tree v{__version__}"
parser.add_argument("-v", "--version", action="version")
parser.add_argument(
"root_dir",
metavar="ROOT_DIR",
nargs="?",
default=".",
help="Generate a full directory tree starting at ROOT_DIR",
)
parser.add_argument(
"-d",
"--dir-only",
action="store_true",
help="Generate a directory-only tree",
)
parser.add_argument(
"-o",
"--output-file",
metavar="OUTPUT_FILE",
nargs="?",
default=sys.stdout,
help="Generate a full directory tree and save it to a file",
)
return parser.parse_args()
"""This module provides RP Tree main module."""
import os
import pathlib
import sys
PIPE = "│"
ELBOW = "└──"
TEE = "├──"
PIPE_PREFIX = "│ "
SPACE_PREFIX = " "
class DirectoryTree:
def __init__(self, root_dir, dir_only=False, output_file=sys.stdout):
self._output_file = output_file
self._generator = _TreeGenerator(root_dir, dir_only)
def generate(self):
tree = self._generator.build_tree()
if self._output_file != sys.stdout:
# Wrap the tree in a markdown code block
tree.insert(0, "```")
tree.append("```")
self._output_file = open(
self._output_file, mode="w", encoding="UTF-8"
)
with self._output_file as stream:
for entry in tree:
print(entry, file=stream)
class _TreeGenerator:
def __init__(self, root_dir, dir_only=False):
self._root_dir = pathlib.Path(root_dir)
self._dir_only = dir_only
self._tree = []
def build_tree(self):
self._tree_head()
self._tree_tail(self._root_dir)
return self._tree
def _tree_head(self):
self._tree.append(f"{self._root_dir}{os.sep}")
self._tree.append(PIPE)
def _tree_tail(self, directory, prefix=""):
entries = self._prepare_entries(directory)
entries_count = len(entries)
for index, entry in enumerate(entries):
connector = ELBOW if index == entries_count - 1 else TEE
if entry.is_dir():
self._add_directory(
entry, index, entries_count, prefix, connector
)
else:
self._add_file(entry, prefix, connector)
def _prepare_entries(self, directory):
entries = directory.iterdir()
if self._dir_only:
entries = [entry for entry in entries if entry.is_dir()]
return entries
entries = sorted(entries, key=lambda entry: entry.is_file())
return entries
def _add_directory(
self, directory, index, entries_count, prefix, connector
):
self._tree.append(f"{prefix}{connector} {directory.name}{os.sep}")
if index != entries_count - 1:
prefix += PIPE_PREFIX
else:
prefix += SPACE_PREFIX
self._tree_tail(
directory=directory,
prefix=prefix,
)
self._tree.append(prefix.rstrip())
def _add_file(self, file, prefix, connector):
self._tree.append(f"{prefix}{connector} {file.name}")
#!/usr/bin/env python3
"""This module provides RP Tree entry point script."""
from rptree.cli import main
if __name__ == "__main__":
main()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册