projecttree-by-almira 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ Metadata-Version: 2.4
2
+ Name: projecttree-by-almira
3
+ Version: 0.1.0
4
+ Summary: A beautiful CLI tool to generate project tree structures.
5
+ Author: Almira
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.11
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: pyperclip>=1.8.2
13
+
14
+ # ProjectTree
@@ -0,0 +1 @@
1
+ # ProjectTree
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,85 @@
1
+ import argparse
2
+ import os
3
+ import sys
4
+ from projecttree.scanner import TreeScanner
5
+ from projecttree.formatter import TreeFormatter
6
+ from projecttree.utils import save_to_file, copy_to_clipboard
7
+
8
+
9
+ def parse_arguments():
10
+ parser = argparse.ArgumentParser(
11
+ description="projecttree — утилита для красивого вывода структуры проекта."
12
+ )
13
+ parser.add_argument(
14
+ "path",
15
+ nargs="?",
16
+ default=".",
17
+ help="Путь к сканируемой директории (по умолчанию: текущая)."
18
+ )
19
+ parser.add_argument(
20
+ "-d", "--depth",
21
+ type=int,
22
+ default=None,
23
+ help="Максимальная глубина отображения дерева."
24
+ )
25
+ parser.add_argument(
26
+ "-i", "--ignore",
27
+ nargs="+",
28
+ default=[],
29
+ help="Список имен файлов/папок для игнорирования."
30
+ )
31
+ parser.add_argument(
32
+ "--dirs-only",
33
+ action="store_true",
34
+ help="Отображать только директории."
35
+ )
36
+ parser.add_argument(
37
+ "-o", "--output",
38
+ type=str,
39
+ default=None,
40
+ help="Экспортировать результат в указанный текстовый файл."
41
+ )
42
+ parser.add_argument(
43
+ "-m", "--markdown",
44
+ action="store_true",
45
+ help="Вывести структуру в формате Markdown."
46
+ )
47
+ parser.add_argument(
48
+ "-c", "--copy",
49
+ action="store_true",
50
+ help="Скопировать результат в буфер обмена."
51
+ )
52
+ return parser.parse_args()
53
+
54
+
55
+ def main():
56
+ args = parse_arguments()
57
+
58
+ if not os.path.exists(args.path):
59
+ print(f"Указанный путь не существует: {args.path}", file=sys.stderr)
60
+ sys.exit(1)
61
+
62
+ scanner = TreeScanner(
63
+ ignore_patterns=args.ignore,
64
+ dirs_only=args.dirs_only,
65
+ max_depth=args.depth
66
+ )
67
+ tree_model = scanner.scan(args.path)
68
+
69
+ if args.markdown:
70
+ result_text = TreeFormatter.to_markdown(tree_model)
71
+ else:
72
+ result_text = TreeFormatter.to_text(tree_model)
73
+
74
+ print(result_text)
75
+ print("-" * 40)
76
+
77
+ if args.output:
78
+ save_to_file(args.output, result_text)
79
+
80
+ if args.copy:
81
+ copy_to_clipboard(result_text)
82
+
83
+
84
+ if __name__ == "__main__":
85
+ main()
@@ -0,0 +1,35 @@
1
+ from projecttree.models import Node
2
+
3
+
4
+ class TreeFormatter:
5
+ @staticmethod
6
+ def to_text(node: Node, prefix: str = "") -> str:
7
+ lines = []
8
+ if not prefix:
9
+ lines.append(node.name + "/")
10
+ prefix = ""
11
+
12
+ count = len(node.children)
13
+ for i, child in enumerate(node.children):
14
+ is_last = (i == count - 1)
15
+ connector = "└── " if is_last else "├── "
16
+
17
+ suffix = "/" if child.is_dir else ""
18
+ lines.append(f"{prefix}{connector}{child.name}{suffix}")
19
+
20
+ if child.is_dir:
21
+ extension = " " if is_last else "│ "
22
+ lines.append(TreeFormatter.to_text(child, prefix + extension))
23
+
24
+ return "\n".join(line for line in lines if line.strip())
25
+
26
+ @staticmethod
27
+ def to_markdown(node: Node, depth: int = 0) -> str:
28
+ indent = " " * depth
29
+ suffix = "/" if node.is_dir else ""
30
+ lines = [f"{indent}- {node.name}{suffix}"]
31
+
32
+ for child in node.children:
33
+ lines.append(TreeFormatter.to_markdown(child, depth + 1))
34
+
35
+ return "\n".join(lines)
@@ -0,0 +1,9 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import List
3
+
4
+ @dataclass
5
+ class Node:
6
+ name: str
7
+ is_dir: bool
8
+ path: str
9
+ children: List['Node'] = field(default_factory=list)
@@ -0,0 +1,48 @@
1
+ import os
2
+ from typing import List, Optional
3
+ from projecttree.models import Node
4
+
5
+ class TreeScanner:
6
+ def __init__(
7
+ self,
8
+ ignore_patterns: Optional[List[str]] = None,
9
+ dirs_only: bool = False,
10
+ max_depth: Optional[int] = None
11
+ ):
12
+ self.ignore_patterns = ignore_patterns or []
13
+ self.dirs_only = dirs_only
14
+ self.max_depth = max_depth
15
+
16
+ self.default_ignore = {'.git', '__pycache__', '.pytest_cache', '.venv', 'venv'}
17
+
18
+ def _should_ignore(self, name: str) -> bool:
19
+ if name in self.default_ignore:
20
+ return True
21
+ for pattern in self.ignore_patterns:
22
+ if pattern in name:
23
+ return True
24
+ return False
25
+
26
+ def scan(self, path: str, current_depth: int = 1) -> Node:
27
+ name = os.path.basename(os.path.abspath(path)) or path
28
+ node = Node(name=name, is_dir=True, path=path)
29
+
30
+ if self.max_depth is not None and current_depth > self.max_depth:
31
+ return node
32
+
33
+ try:
34
+ entries = sorted(os.scandir(path), key=lambda e: (not e.is_dir(), e.name.lower()))
35
+ except PermissionError:
36
+ return node
37
+
38
+ for entry in entries:
39
+ if self._should_ignore(entry.name):
40
+ continue
41
+
42
+ if entry.is_dir():
43
+ child_node = self.scan(entry.path, current_depth + 1)
44
+ node.children.append(child_node)
45
+ elif not self.dirs_only:
46
+ node.children.append(Node(name=entry.name, is_dir=False, path=entry.path))
47
+
48
+ return node
@@ -0,0 +1,17 @@
1
+ import sys
2
+ import pyperclip
3
+
4
+ def save_to_file(filepath: str, content: str) -> None:
5
+ try:
6
+ with open(filepath, "w", encoding="utf-8") as f:
7
+ f.write(content)
8
+ print(f"Структура успешно экспортирована в: {filepath}")
9
+ except Exception as e:
10
+ print(f"Ошибка при записи в файл: {e}", file=sys.stderr)
11
+
12
+ def copy_to_clipboard(content: str) -> None:
13
+ try:
14
+ pyperclip.copy(content)
15
+ print("Структура успешно скопирована в буфер обмена!")
16
+ except Exception as e:
17
+ print(f"Не удалось скопировать в буфер обмена: {e}", file=sys.stderr)
@@ -0,0 +1,14 @@
1
+ Metadata-Version: 2.4
2
+ Name: projecttree-by-almira
3
+ Version: 0.1.0
4
+ Summary: A beautiful CLI tool to generate project tree structures.
5
+ Author: Almira
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.11
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: pyperclip>=1.8.2
13
+
14
+ # ProjectTree
@@ -0,0 +1,14 @@
1
+ README.md
2
+ pyproject.toml
3
+ projecttree/__init__.py
4
+ projecttree/cli.py
5
+ projecttree/formatter.py
6
+ projecttree/models.py
7
+ projecttree/scanner.py
8
+ projecttree/utils.py
9
+ projecttree_by_almira.egg-info/PKG-INFO
10
+ projecttree_by_almira.egg-info/SOURCES.txt
11
+ projecttree_by_almira.egg-info/dependency_links.txt
12
+ projecttree_by_almira.egg-info/entry_points.txt
13
+ projecttree_by_almira.egg-info/requires.txt
14
+ projecttree_by_almira.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ projecttree = projecttree.cli:main
@@ -0,0 +1,26 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "projecttree-by-almira"
7
+ version = "0.1.0"
8
+ description = "A beautiful CLI tool to generate project tree structures."
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Almira" }
14
+ ]
15
+ classifiers = [
16
+ "Programming Language :: Python :: 3",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Operating System :: OS Independent",
19
+ ]
20
+
21
+ dependencies = [
22
+ "pyperclip>=1.8.2",
23
+ ]
24
+
25
+ [project.scripts]
26
+ projecttree = "projecttree.cli:main"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+