Skip to main content

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:

  1. A Python dictionary passed in directly
  2. A JSON file read from disk — filesystem-shaped or not
  3. 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. tree behaves 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_patterns matches 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

arbol_tree-0.1.0.tar.gz (11.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

arbol_tree-0.1.0-py3-none-any.whl (13.2 kB view details)

Uploaded Python 3

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

Hashes for arbol_tree-0.1.0.tar.gz
Algorithm Hash digest
SHA256 2d8fc8a4095084b87ee433e07d946102a81a8461b1132ca4b82ad2b77d83fa7f
MD5 ee7ae57742062b5629bd66c05aa9ee5b
BLAKE2b-256 cb1c0b2ef97770477da750fbb3af2a01f764699128ef23f4d2a45707a91aac18

See more details on using hashes here.

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

Hashes for arbol_tree-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ddf70028043d040944bb91102da1b7017f26f83f6e542e6b7001d0772b0b6854
MD5 c0c5ff1781a0b5b320cb95d302426759
BLAKE2b-256 3d2d56d8f64b5ed61a1d7cba325a6918dd595845bb7857401b2befbf05e6d933

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page