Metadata-Version: 2.4
Name: vcti-path-tree
Version: 1.1.1
Summary: VCollab Path Tree - directory tree scanning and serialization using Pydantic models
Author: Visual Collaboration Technologies Inc.
Requires-Python: <3.15,>=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic
Requires-Dist: vcti-enum>=1.0.3
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Provides-Extra: lint
Requires-Dist: ruff; extra == "lint"
Dynamic: license-file

# Path Tree

## Purpose

VCollab applications frequently need to scan directory structures —
listing files and subdirectories recursively, representing them as
structured data for API responses, and generating CLI-style tree
visualizations.

The `vcti-path-tree` package provides Pydantic models (`File`,
`Directory`) for representing file system trees and entry points —
`get_path_tree()` for scanning directories into models,
`get_cli_tree()` for generating tree visualizations,
`walk_tree()` for iterating over scanned trees, and
`get_tree_stats()` for summary statistics.

Requires Python 3.12+. Dependencies: `pydantic`, `vcti-enum`.

---

## Installation

### From GitHub (recommended for development)

```bash
# Latest main branch
pip install vcti-path-tree



### In `requirements.txt`

```
vcti-path-tree>=1.1.1
```

### In `pyproject.toml` dependencies

```toml
dependencies = [
    "vcti-path-tree>=1.1.1",
]
```

---

## Quick Start

```python
from pathlib import Path
from vcti.pathtree import get_path_tree, get_cli_tree

# Scan a directory into Pydantic models
tree = get_path_tree(Path("/data/project"))

# Generate a CLI-style tree visualization
lines = get_cli_tree(tree)
for line in lines:
    print(line)
# project/
# ├── src/
# │   ├── main.py
# │   └── utils.py
# └── README.md

# Access model attributes
root = tree[0]
print(root.name)       # "project"
print(root.type)       # PathType.DIRECTORY
for child in root.children:
    print(f"  {child.name} ({child.type})")

# Relative paths with posix format
tree = get_path_tree(
    Path("/data/project"),
    base_path=Path("/data"),
    as_posix=True
)
print(tree[0].path)    # "project"

# Skip root directory, get only children
children = get_path_tree(Path("/data/project"), skip_root=True)

# Limit recursion depth
tree = get_path_tree(Path("/data/project"), max_depth=2)

# Filter: only include .py files and directories
tree = get_path_tree(
    Path("/data/project"),
    filter_fn=lambda p: p.is_dir() or p.suffix == ".py",
)

# Include file timestamps
tree = get_path_tree(Path("/data/project"), include_metadata=True)

# Serialize to JSON (Pydantic models)
import json
print(json.dumps([node.model_dump() for node in tree], indent=2))
```

---

## Public API

| Name | Kind | Description |
|------|------|-------------|
| `PathType` | Enum | `FILE` or `DIRECTORY` |
| `PathBase` | Model | Base Pydantic model with `name`, `path`, `type` |
| `File` | Model | File node with `size`, optional `modified_time`/`created_time` |
| `Directory` | Model | Directory node with `children` list, optional timestamps |
| `PathTree` | Type alias | `list[Directory \| File]` |
| `FilterFn` | Type alias | `Callable[[Path], bool]` for path filtering |
| `TreeStats` | Model | Summary stats: `total_files`, `total_dirs`, `total_size`, `max_depth` |
| `handle_file(...)` | Function | Create a File model from a Path |
| `handle_directory(...)` | Function | Create a Directory model recursively |
| `get_path_tree(...)` | Function | Scan path into a list of models |
| `get_cli_tree(path_tree)` | Function | Generate CLI tree visualization lines |
| `walk_tree(tree)` | Function | Yield `(dir_path, dirs, files)` tuples like `os.walk` |
| `get_tree_stats(tree)` | Function | Compute summary statistics for a tree |
| `parse_path_tree(data)` | Function | Deserialize list of dicts into a PathTree |

---

## Limitations

- **Symlinks are followed.** The scanner uses Python's default behavior
  (`Path.stat()`, `Path.iterdir()`), which follows symbolic links. Use
  `max_depth` to guard against cycles from recursive symlinks.
- **Permission errors propagate.** If a file or directory is not readable,
  `OSError` is raised. There is no partial-tree or skip-on-error mode.
- **Entire tree is materialized in memory.** Not suitable for very large
  directory trees where streaming would be preferred.

---

## Documentation

- [Design](docs/design.md) — Concepts, architecture decisions, and trade-offs
- [Source Guide](docs/source-guide.md) — Execution flow traces for developers
- [API Reference](docs/api.md) — Autodoc for all modules
