Arbol
Draw tree structures in the terminal, in the style of the Linux tree command.
Arbol has three input sources, all drawn by the same renderer:
- A Python dictionary passed in directly
- A JSON file read from disk — filesystem-shaped or not
- A filesystem directory walked recursively
$ arbol tests/data/sample_tree -I 'datasets|assets|suite|scripts' -L 3
tests/data/sample_tree
├── docs
│ ├── images
│ │ ├── diagram.svg
│ │ └── logo.png
│ ├── api.md
│ ├── changelog.md
│ └── guide.md
├── src
│ ├── core
│ │ ├── utils
│ │ ├── engine.py
│ │ └── parser.py
│ ├── plugins
│ │ ├── export.py
│ │ └── importer.py
│ └── __init__.py
├── vendor
│ ├── .hidden
│ │ ├── .DS_Store
│ │ ├── .swp
│ │ ├── build.log
│ │ ├── cache.tmp
│ │ ├── notes.txt.bak
│ │ ├── session.lock
│ │ └── Thumbs.db
│ ├── bundle.min.css
│ └── legacy.js
├── .env.example
├── config.yaml
└── README.md
Hidden entries show by default — .hidden/ and .env.example are there
without asking. Directories sort before files, then case-insensitively.
Installing
The distribution is named arbol-tree, since arbol on PyPI is an
unrelated package. The import name and the command are both arbol.
pip install arbol-tree
It is not published yet, so for now run it from a path. From the project directory:
uv run arbol .
With uvx, from anywhere:
uvx --from /path/to/arbol arbol .
Or build a wheel and run that:
uv build
uvx --from ./dist/arbol_tree-0.1.0-py3-none-any.whl arbol .
Command line
arbol [OPTIONS] [PATH]
PATH is a directory to walk or a JSON file to read, and defaults to the
current directory. Arbol works out which it is; there is no mode flag.
| Option | Description |
|---|---|
-L, --level |
Maximum display depth, counting levels below the root |
-I, --ignore |
Wildcard pattern to skip, at any depth. Repeatable |
-o, --output |
Save the intermediate JSON here instead of a temporary file |
-V, --version |
Show the version and exit |
Walking a directory includes everything by default — hidden entries and all
depths. That differs from tree, which hides dotfiles unless given -a. In a
repository, expect .git to show up.
Ignore patterns
-I takes the same wildcard patterns as tree -I, matched against each
entry's name — never its path, so -I 'src/*.pyc' matches nothing, exactly
as in tree.
| Operator | Matches |
|---|---|
* |
Zero or more characters |
? |
Any single character |
[abc], [a-z] |
One character from the set |
[^abc] |
One character not in the set |
| |
Either alternate |
trailing / |
Restricts the pattern to directories |
The trailing slash is the useful one: it is the difference between hiding a folder and hiding everything that shares its naming convention.
uv run arbol . -I '__*__/' -I '*.pyc'
That drops every __pycache__ folder and every stray .pyc, while keeping
__init__.py — the slash confined the first pattern to directories, and the
second names files. Ignoring a directory ignores everything beneath it.
-I is repeatable, and | does the same job inside a single pattern:
uv run arbol . -I '.*/|__*__/|node_modules'
Matching is case-sensitive, as in tree without --ignore-case.
The walk options describe a walk, so passing them alongside a JSON file is an error rather than a silent no-op.
Drawing a JSON file
A JSON document needs no filesystem structure. Any nesting of objects, arrays and strings draws:
{
"ROOT": "Acme Corp",
"Engineering": {"Backend": ["api", "workers"], "Frontend": ["web", "mobile"]},
"Operations": {"Support": "tier-1"}
}
Acme Corp
├── Engineering
│ ├── Backend
│ │ ├── api
│ │ └── workers
│ └── Frontend
│ ├── web
│ └── mobile
└── Operations
└── Support
└── tier-1
The ROOT key names the root node and is not drawn as a branch. Everything
else follows three rules: an object contributes one branch per key, an array
contributes one child per item, and anything else becomes a leaf.
Saving the JSON from a directory walk and drawing it back round-trips:
uv run arbol . -o tree.json && uv run arbol tree.json
Python API
Two objects, kept deliberately apart. JsonBuilder decides what is in the
tree; ArbolTerminalView draws exactly what it is given and filters nothing.
import arbol
builder = arbol.JsonBuilder(ignore_patterns=["__*__/", "*.pyc"], level=2)
json_path = builder.write_directory("some/dir")
view = arbol.ArbolTerminalView()
print(view.render(arbol.JsonBuilder.load(json_path)))
Module-level shortcuts cover the simple cases:
arbol.render({"ROOT": "r", "a": ["x", "y"]})
arbol.print_tree(arbol.load_json("tree.json"))
arbol.write_directory_json("some/dir", level=2)
By default write_directory puts the JSON in a temporary folder and leaves it
there for you to clean up. Pass output_path to save it somewhere real.
Behavior worth knowing
- Symlinked directories are listed but never followed, so a symlink loop cannot
blow up the output.
treebehaves the same without-l. - A directory that cannot be read is drawn as empty rather than aborting the walk.
- Entries sort directories first, then files, case-insensitively — the same
order as
tree --dirsfirst. ignore_patternsmatches names at any depth, never paths, and applies to files and directories alike unless a trailing/narrows it.- Nothing is hidden unless a pattern says so. There is no
-a, because the default already shows every entry.
Development
uv sync
uv run pytest
uv run ruff check .
uv run ruff format .
Releasing to PyPI, including the TestPyPI rehearsal, is written up in RELEASING.md.
License
MIT. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file arbol_tree-0.1.0.tar.gz.
File metadata
- Download URL: arbol_tree-0.1.0.tar.gz
- Upload date:
- Size: 11.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2d8fc8a4095084b87ee433e07d946102a81a8461b1132ca4b82ad2b77d83fa7f
|
|
| MD5 |
ee7ae57742062b5629bd66c05aa9ee5b
|
|
| BLAKE2b-256 |
cb1c0b2ef97770477da750fbb3af2a01f764699128ef23f4d2a45707a91aac18
|
File details
Details for the file arbol_tree-0.1.0-py3-none-any.whl.
File metadata
- Download URL: arbol_tree-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ddf70028043d040944bb91102da1b7017f26f83f6e542e6b7001d0772b0b6854
|
|
| MD5 |
c0c5ff1781a0b5b320cb95d302426759
|
|
| BLAKE2b-256 |
3d2d56d8f64b5ed61a1d7cba325a6918dd595845bb7857401b2befbf05e6d933
|