Skip to content

Commit cc710aa

Browse files
committed
Added CLI tool, max file depth, and path filtering
1 parent 9e39d16 commit cc710aa

File tree

12 files changed

+512
-130
lines changed

12 files changed

+512
-130
lines changed

README.md

+178-79
Original file line numberDiff line numberDiff line change
@@ -6,86 +6,7 @@ There are a bunch existing solutions out there for drawing directory structures
66

77
`ascii-tree` provides an easy-to-use interface to display any tree-like data as a string.
88

9-
## Drawing a Directory Tree
10-
One batteries-included feature of `ascii-tree` is the ability to draw directory trees.
11-
12-
This also provides a good example of how you might customize rendering for custom tree data.
139

14-
```python
15-
import ascii_tree
16-
tree = ascii_tree.renderable_dir_tree(
17-
"./tests/fixtures"
18-
)
19-
print(ascii_tree.render(tree))
20-
```
21-
Output:
22-
```
23-
fixtures /
24-
└─ root_dir /
25-
├─ child_dir_one /
26-
│ ├─ grandchild_dir_one /
27-
│ │ └─ great_grandchild_file_one.txt
28-
│ └─ grandchild_file_one.txt
29-
└─ child_dir_two /
30-
├─ grandchild_dir_two /
31-
│ └─ great_grandchild_file_two.txt
32-
└─ grandchild_file_two.txt
33-
```
34-
By default, this will recurse until all directories and files are visited.
35-
### Setting Traversal Depth
36-
By providing a `max_depth` argument, you can only search directories up to a certain level of nesting:
37-
```python
38-
import ascii_tree
39-
tree = ascii_tree.renderable_dir_tree(
40-
"./tests/fixtures",
41-
max_depth=2
42-
)
43-
print(ascii_tree.render(tree))
44-
```
45-
Output:
46-
```
47-
fixtures /
48-
└─ root_dir /
49-
├─ child_dir_one / ...
50-
└─ child_dir_two / ...
51-
```
52-
The slashes after directories and the ellipses (`...`) after max depth can be controlled with parameters on `renderable_dir_tree`.
53-
```python
54-
import ascii_tree
55-
tree = ascii_tree.renderable_dir_tree(
56-
"./tests/fixtures",
57-
max_depth=2,
58-
slash_after_dir=False,
59-
ellipsis_after_max_depth=False
60-
)
61-
```
62-
Output:
63-
```
64-
fixtures
65-
└─ root_dir
66-
├─ child_dir_one
67-
└─ child_dir_two
68-
```
69-
### Dealing with Permission Errors
70-
Finally, if you are traversing files with mixed permission levels, it can be useful to skip files that would otherwise cause a `PermissionError` when access isn't allowed. Use the
71-
`skip_if_no_permission` parameter:
72-
```python
73-
import ascii_tree
74-
tree = ascii_tree.renderable_dir_tree(
75-
"here/be/dragons",
76-
skip_if_no_permission=True
77-
)
78-
print(ascii_tree.render(tree))
79-
```
80-
Output:
81-
```
82-
dragons /
83-
├─ pendor /
84-
│ └─ yevaud.txt
85-
├─ lonely_mountain [Permission Denied]
86-
└─ westeros /
87-
└─ balereon.txt
88-
```
8910
## Building a Tree from Scratch
9011

9112
Trees can be built up from a chain of `TextRenderNode` instances. `TextRenderNode` is extremely simple; just a `display` and a `children` attribute.
@@ -232,3 +153,181 @@ root
232153
· great_grandchild_four
233154
· child_two
234155
```
156+
157+
## Drawing a Directory Tree
158+
One batteries-included feature of `ascii-tree` is the ability to draw directory trees.
159+
160+
This also provides a good example of how you might customize rendering for custom tree data.
161+
162+
```python
163+
import ascii_tree
164+
tree = ascii_tree.renderable_dir_tree(
165+
"./tests/fixtures"
166+
)
167+
print(ascii_tree.render(tree))
168+
```
169+
Output:
170+
```
171+
fixtures /
172+
└─ root_dir /
173+
├─ child_dir_one /
174+
│ ├─ grandchild_dir_one /
175+
│ │ └─ great_grandchild_file_one.txt
176+
│ └─ grandchild_file_one.txt
177+
└─ child_dir_two /
178+
├─ grandchild_dir_two /
179+
│ └─ great_grandchild_file_two.txt
180+
└─ grandchild_file_two.txt
181+
```
182+
By default, this will recurse until all directories and files are visited.
183+
184+
### Filtering Files and Directories
185+
You can filter files and directories by providing a `dir_filter` and/or `file_filter` argument to `renderable_dir_tree`. This argument should be a function that takes a `Path` object, and returns `True` if the file or directory should be included in the tree, and `False` otherwise.
186+
187+
Directories are filtered before files, so if a directory is excluded, all of its contents will be excluded as well.
188+
189+
```python
190+
import ascii_tree
191+
tree = ascii_tree.renderable_dir_tree(
192+
"./tests/fixtures",
193+
dir_filter=lambda x: x.name != "child_dir_one",
194+
file_filter=lambda x: x.name != "grandchild_file_one.txt"
195+
)
196+
print(ascii_tree.render(tree))
197+
```
198+
Output:
199+
```
200+
fixtures /
201+
└─ root_dir /
202+
└─ child_dir_two /
203+
├─ grandchild_dir_two /
204+
│ └─ great_grandchild_file_two.txt
205+
└─ grandchild_file_two.txt
206+
```
207+
208+
### Setting Traversal Depth
209+
By providing a `max_depth` argument, you can only search directories up to a certain level of nesting:
210+
```python
211+
import ascii_tree
212+
tree = ascii_tree.renderable_dir_tree(
213+
"./tests/fixtures",
214+
max_depth=2
215+
)
216+
print(ascii_tree.render(tree))
217+
```
218+
Output:
219+
```
220+
fixtures /
221+
└─ root_dir /
222+
├─ child_dir_one / ...
223+
└─ child_dir_two / ...
224+
```
225+
The slashes after directories and the ellipses (`...`) after max depth can be controlled with parameters on `renderable_dir_tree`.
226+
227+
```python
228+
tree = ascii_tree.renderable_dir_tree(
229+
"./tests/fixtures",
230+
max_depth=2,
231+
slash_after_dir=False,
232+
ellipsis_after_max_depth=False
233+
)
234+
235+
print(ascii_tree.render(tree))
236+
```
237+
238+
Output:
239+
```
240+
fixtures
241+
└─ root_dir
242+
├─ child_dir_one
243+
└─ child_dir_two
244+
```
245+
246+
### Limiting File Lists
247+
248+
You can also limit the number of files displayed in each directory by using the `max_file_count` parameter:
249+
250+
```python
251+
import ascii_tree
252+
tree = ascii_tree.renderable_dir_tree(
253+
"./tests/files_list",
254+
max_file_count=2
255+
)
256+
257+
```
258+
Output:
259+
```
260+
files_list \
261+
├─ file_one.txt
262+
├─ file_two.txt
263+
└─ ...
264+
```
265+
266+
And, like with directories and `max_depth`, you can limit the number of files displayed in each directory by using the `max_file_count` parameter:
267+
```python
268+
import ascii_tree
269+
tree = ascii_tree.renderable_dir_tree(
270+
"./tests/files_list",
271+
max_file_count=1
272+
)
273+
```
274+
Output:
275+
files_list \
276+
└─ file_one.txt
277+
```
278+
279+
### Dealing with Permission Errors
280+
Finally, if you are traversing files with mixed permission levels, it can be useful to skip files that would otherwise cause a `PermissionError` when access isn't allowed. Use the
281+
`skip_if_no_permission` parameter:
282+
283+
```python
284+
import ascii_tree
285+
tree = ascii_tree.renderable_dir_tree(
286+
"here/be/dragons",
287+
skip_if_no_permission=True
288+
)
289+
print(ascii_tree.render(tree))
290+
```
291+
Output:
292+
```
293+
dragons /
294+
├─ pendor /
295+
│ └─ yevaud.txt
296+
├─ lonely_mountain [Permission Denied]
297+
└─ westeros /
298+
└─ balereon.txt
299+
```
300+
301+
### Directory Tree CLI
302+
`ascii-tree` also provides a CLI for drawing directory trees. Just run `dir-tree` with a directory path as an argument to draw the tree.
303+
304+
```bash
305+
$ dir-tree tests/fixtures --depth 2
306+
fixtures /
307+
└─ root_dir /
308+
├─ child_dir_one / ...
309+
└─ child_dir_two / ...
310+
```
311+
312+
The CLI supports all of the same options as the `renderable_dir_tree` function, including filters in the form of glob-style patterns.
313+
314+
```bash
315+
$ dir-tree tests/fixtures --depth 2 --dir-filter "*child_dir_one*" --file-filter "*.txt"
316+
```
317+
318+
Here are the rest of the arguments, options, and flags:
319+
320+
| Option | Description |
321+
|-----------------------------|----------------------------------------------|
322+
| --flat | Do not build the tree recursively. |
323+
| --max-depth | Maximum depth to build the tree. |
324+
| --max-files | Maximum number of files per directory. |
325+
| --dir-pattern | Glob pattern to filter directories. |
326+
| --file-pattern | Glob pattern to filter files. |
327+
| --no-slash | Do not add a trailing slash after folders |
328+
| --no-ellipsis-depth | Do not add '...' for folders past max depth. |
329+
| --no-ellipsis-files | Do not add '...' for files past max count. |
330+
| --raise-on-permission-error | Raise an exception on permission errors |
331+
| --style | Rendering style for the tree. |
332+
| --width | Width of horizontal lines in the tree. |
333+
| --spacing | Spaces between decorations and display text. |

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ dev = [
99

1010
[project]
1111
name = "ascii-tree"
12-
version = "0.1.0"
12+
version = "0.2.0"
1313
description = "Generate ASCII representations of tree-like data"
1414
authors = [
1515
{name = "sharpencrag", email = "[email protected]"},

scripts/dir-tree.pyz

34.3 KB
Binary file not shown.

0 commit comments

Comments
 (0)