Metadata-Version: 2.4
Name: flextree
Version: 0.1.7
Summary: FlexTree - A flexible and intuitive Python library for creating and manipulating tree data structures
Home-page: https://github.com/znzhao/flextree
Author: Zhenning Zhao
Author-email: Zhenning Zhao <znzhaopersonal@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/znzhao/flextree
Project-URL: Bug Reports, https://github.com/znzhao/flextree/issues
Project-URL: Source, https://github.com/znzhao/flextree
Project-URL: Documentation, https://github.com/znzhao/flextree#readme
Keywords: tree,data-structure,node,hierarchy,graph
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.6
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: author
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-python

# FlexTree

A flexible and intuitive Python library for creating and manipulating tree data structures.

> **Warning**
> Some code or documentation in this project may be generated by AI. While the developer has tested the code, please review and validate all outputs before using them in production. Use at your own risk.

## Features

- **TreeNode**: Individual nodes with name, content, and parent-child relationships
- **Tree**: Complete tree structure with operations for insertion, deletion, and modification
- **JSON Serialization**: Save and load trees to/from JSON files
- **Tree Visualization**: ASCII art tree drawing functionality
- **Flexible Content**: Store any Python object as node content
- **Search Operations**: Find nodes by name or index
- **Tree Statistics**: Calculate depth, width, and node count metrics

## Installation
Install using pip:
```bash
pip install flextree
```

Or, you can install by cloning this repository:

```bash
git clone https://github.com/znzhao/flextree.git
cd flextree
pip install -e .
```

## Quick Start

### Creating a Flex Tree

```python
from flextree import TreeNode, Tree, draw_tree

# Create nodes
root = TreeNode("Company", "Acme Corp")
engineering = TreeNode("Engineering", "Tech Department")
marketing = TreeNode("Marketing", "Marketing Department")
backend = TreeNode("Backend", "Server Team")
frontend = TreeNode("Frontend", "UI Team")

# Build tree structure
root.add_child(engineering)
root.add_child(marketing)
engineering.add_child(backend)
engineering.add_child(frontend)

# Create a tree object
company_tree = Tree(root)

# Visualize the tree
draw_tree(root)
```

Output:
```
└── Company: Acme Corp
    ├── Engineering: Tech Department
    │   ├── Backend: Server Team
    │   └── Frontend: UI Team
    └── Marketing: Marketing Department
```

### Working with Tree Operations

```python
# Insert a new department
new_dept = TreeNode("HR", "Human Resources")
company_tree.insert("Company", new_dept)

# Modify existing content
company_tree.alter("Backend", "Backend Development Team")

# Get a subtree
eng_subtree = company_tree.get("Engineering")
print(eng_subtree.summary())

# Delete a node
company_tree.delete("HR")
```

### Pythonic Tree Navigation with getitem

Flex Tree supports intuitive Python-style indexing for tree navigation using square bracket notation. This makes working with trees feel natural and pythonic.

```python
# Tree objects support getitem operations
company_tree = Tree(root)

# Access child by name - returns Tree object
eng_dept = company_tree["Engineering"]
print(f"Department: {eng_dept.root.name}")

# Multiple selection using string lists
departments = company_tree[["Engineering", "Marketing"]]
print(f"Selected: {[tree.root.name for tree in departments]}")

# Chain operations for deep navigation
if eng_dept:
    # Further navigation on the subtree
    print(f"Engineering has {len(eng_dept.root.children)} teams")
```

**Important Notes:**
- Only `Tree` objects support getitem operations (`tree[key]`)
- `TreeNode` objects do not support getitem - use `node.children` for direct access
- Tree getitem returns `Tree` objects (single) or `List[Tree]` (multiple)
- Multiple selection only supports string-only lists: `tree[["name1", "name2"]]`
- For other access patterns (by index, slicing), work with `TreeNode.children` directly

### Storing Complex Data

```python
# Nodes can store any Python object
employee_data = {
    "name": "John Doe",
    "role": "Senior Developer",
    "skills": ["Python", "JavaScript", "Docker"],
    "start_date": "2023-01-15"
}

employee_node = TreeNode("john_doe", employee_data)
backend.add_child(employee_node)
```

### JSON Serialization

```python
# Save tree to JSON file
company_tree.save_json("company_structure.json")

# Load tree from JSON file
loaded_tree = Tree.load_json("company_structure.json")
```

### Tree Statistics

```python
# Get tree dimensions
print(f"Max depth: {company_tree.max_depth()}")
print(f"Max width: {company_tree.max_width()}")
print(f"Node count: {company_tree.count()}")
# Get node summary
print(company_tree.summary())
```

## Tree Visualization with draw_tree

The `draw_tree` function provides a beautiful ASCII art representation of your tree structure using Unicode box-drawing characters. This is perfect for debugging, documentation, or simply understanding your tree's structure.

### Basic Usage

```python
from flextree import TreeNode, draw_tree

# Create a Flex tree
root = TreeNode("root", "I am root")
child1 = TreeNode("child1", "First child")
child2 = TreeNode("child2", "Second child")
grandchild = TreeNode("grandchild", "I'm nested!")

root.add_child(child1)
root.add_child(child2)
child1.add_child(grandchild)

# Draw the tree
draw_tree(root)
```

Output:
```
└── root: I am root
    ├── child1: First child
    │   └── grandchild: I'm nested!
    └── child2: Second child
```

### Drawing Subtrees

You can draw any subtree by passing any node as the starting point:

```python
# Draw only the subtree starting from child1
draw_tree(child1)
```

Output:
```
└── child1: First child
    └── grandchild: I'm nested!
```

### Special Content Handling

The `draw_tree` function has special handling for dictionary content. By default, if your node's content is a dictionary containing a `'definition'` key, it will display that value instead of the entire dictionary:

```python
# Create nodes with dictionary content
root = TreeNode("concept", {"definition": "A tree data structure", "type": "data_structure"})
child = TreeNode("node", {"definition": "A single element in the tree", "properties": ["name", "content"]})

root.add_child(child)
draw_tree(root)
```

Output:
```
└── concept: A tree data structure
    └── node: A single element in the tree
```

### Custom Dictionary Key

You can specify a custom key to display from dictionary content using the `key` parameter:

```python
# Create nodes with custom dictionary keys
root = TreeNode("product", {"name": "Flex Tree Library", "description": "Tree data structure", "version": "1.0"})
child = TreeNode("feature", {"name": "JSON Export", "type": "functionality"})

root.add_child(child)

# Use 'name' key instead of 'definition'
draw_tree(root, key="name")
```

Output:
```
└── product: Flex Tree Library
    └── feature: JSON Export
```

Without a matching key, the entire dictionary would be displayed:

```python
root = TreeNode("data", {"key": "value", "number": 42})
draw_tree(root, key="description")  # Key doesn't exist
```

Output:
```
└── data: {'key': 'value', 'number': 42}
```

### Complex Tree Visualization

Here's a more complex example showing different content types:

```python
# Create a knowledge tree
knowledge = TreeNode("Programming", "Software Development")

# Programming languages
languages = TreeNode("Languages", {"definition": "Programming languages", "count": 3})
python = TreeNode("Python", {"definition": "High-level programming language", "year": 1991})
javascript = TreeNode("JavaScript", {"definition": "Web programming language", "year": 1995})
java = TreeNode("Java", {"definition": "Object-oriented programming language", "year": 1995})

# Concepts
concepts = TreeNode("Concepts", "Core programming concepts")
oop = TreeNode("OOP", {"definition": "Object-Oriented Programming", "paradigm": "object-oriented"})
functional = TreeNode("Functional", {"definition": "Functional Programming", "paradigm": "functional"})

# Build the tree
knowledge.add_child(languages)
knowledge.add_child(concepts)
languages.add_child(python)
languages.add_child(javascript)
languages.add_child(java)
concepts.add_child(oop)
concepts.add_child(functional)

# Visualize
draw_tree(knowledge)
```

Output:
```
└── Programming: Software Development
    ├── Languages: Programming languages
    │   ├── Python: High-level programming language
    │   ├── JavaScript: Web programming language
    │   └── Java: Object-oriented programming language
    └── Concepts: Core programming concepts
        ├── OOP: Object-Oriented Programming
        └── Functional: Functional Programming
```

### Using with Tree Objects

You can also use `draw_tree` with `Tree` objects by accessing their root:

```python
tree = Tree(root)
draw_tree(tree.root)

# Or use the convenient .draw() method
tree.draw()

# With custom key
tree.draw(key="name")
```

### Convenient .draw() Methods

Both `TreeNode` and `Tree` objects have a convenient `.draw()` method:

```python
# Draw from any TreeNode
node.draw()
node.draw(key="custom_key")

# Draw entire Tree
tree.draw()
tree.draw(key="custom_key")
```

### Tips for Better Visualization

1. **Keep node names concise**: Long names can make the tree hard to read
2. **Use meaningful content**: The content appears after the colon, so make it descriptive
3. **Use the 'definition' key**: For dictionary content, use a 'definition' key for cleaner output
4. **Consider tree depth**: Very deep trees might be hard to read in console output

### Unicode Characters Used

The `draw_tree` function uses these Unicode box-drawing characters:
- `└──` (U+2514 U+2500 U+2500): For the last child at each level
- `├──` (U+251C U+2500 U+2500): For intermediate children
- `│   ` (U+2502): For vertical continuation lines
- `    ` (4 spaces): For padding after the last child

## API Reference

### TreeNode

#### Constructor
- `TreeNode(name: str, content: Any = None)`: Create a new tree node

#### Methods
- `add_child(child: TreeNode)`: Add a child node
- `remove_child(child: Union[TreeNode, str, int])`: Remove a child by node, name, or index
- `get_child(key: Union[str, int])`: Get child by name or index
- `set_content(content: Any)`: Update node content
- `get_subtree(name: str)`: Find and return subtree by node name
- `to_dict()`: Convert node and its subtree to dictionary
- `from_dict(data: Dict)`: Create node from dictionary (static method)
- `max_depth()`: Calculate maximum depth from this node
- `max_width()`: Calculate maximum width from this node
- `summary()`: Get a formatted summary of the node
- `draw(key: str = "definition")`: Print ASCII art representation of the node and its subtree

### Tree

#### Constructor
- `Tree(root: TreeNode)`: Create a tree with the given root node

#### Methods
- `insert(parent_name: str, node: TreeNode)`: Insert node under specified parent
- `delete(node_name: str)`: Delete node by name
- `alter(node_name: str, new_content: Any)`: Change content of specified node
- `get(key: Union[str, int])`: Get subtree by name or index
- `save_json(filepath: str)`: Save tree to JSON file
- `load_json(filepath: str)`: Load tree from JSON file (static method)
- `max_depth()`: Get maximum depth of entire tree  
- `max_width()`: Get maximum width of entire tree
- `summary()`: Get formatted summary of the tree
- `draw(key: str = "definition")`: Print ASCII art representation of the entire tree

### Utility Functions

#### draw_tree
- `draw_tree(node: TreeNode, prefix: str = "", is_last: bool = True, key: str = "definition")`: Print ASCII art representation of tree

**Parameters:**
- `node` (TreeNode): The root node of the tree/subtree to visualize
- `prefix` (str, optional): Internal parameter for indentation. Leave as default.
- `is_last` (bool, optional): Internal parameter for formatting. Leave as default.
- `key` (str, optional): Dictionary key to display for dict content. Defaults to "definition".

**Special Features:**
- Uses Unicode box-drawing characters for clean tree visualization
- Customizable handling for dictionary content with specified key
- Recursively displays entire subtree structure
- Works with any TreeNode as starting point

**Usage Examples:**
```python
# Basic usage - draw entire tree
draw_tree(root_node)

# Draw subtree starting from any node
draw_tree(some_child_node)

# Use custom dictionary key
draw_tree(root_node, key="name")

# The function automatically handles the formatting
```

## Examples

The Flex Tree package includes ready-to-run example files that demonstrate all the key features:

### Running the Examples

```python
from flextree import examples
examples()
```

## Requirements

- Python 3.6+
- No external dependencies for core functionality

## Contributing

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Changelog

### Version 0.1.6
- Maintained backward compatibility with all existing features
- Prepared for future enhancements and optimizations
- Consolidated changelog documentation

### Version 0.1.5
- Added pythonic getitem functionality for Tree objects
- Enhanced examples with copy-paste ready CODE/OUTPUT format
- Improved documentation with comprehensive getitem usage guide
- Updated TreeNode behavior: removed getitem support (use Tree objects instead)
- Added comprehensive test coverage for count and getitem operations
- Refined Tree getitem to support string-only lists for multiple selection
- Updated package documentation and README with getitem introduction

### Version 0.1.4
- Added count() methods to TreeNode and Tree classes
- Enhanced tree statistics functionality
- Updated examples and documentation

### Version 0.1.3
- Package name changed to "Flex Tree"
- Improved package structure and imports
- Added quick_examples and examples functions to public API

### Version 0.1.2
- Bug fixes and improvements
- Enhanced tree manipulation methods

### Version 0.1.1
- Minor updates and documentation improvements

### Version 0.1.0
- Initial release
- Basic tree node and tree operations
- JSON serialization support
- Tree visualization
- Comprehensive test suite
