Fangorn
Nested Sets aka Modified Pre-order Tree Traversal (MPTT) SQL tree implemented in Python for MySQL and SQLite. Uses both traversal markup (left, right) and adjacency list parentId for more ad-hoc query flexibility.
Provides tree structure validation and “memorisation” via SQLite :memory: for quick reads.
Example
We want to achieve the following tree. Node is represented by name id → parentId (l, r). To output a tree this way fangorn.test.visualize function can be used.
R 1 → None (1, 18)
└─A1 2 → 1 (2, 5)
└─B1 3 → 2 (3, 4)
└─A2 4 → 1 (6, 13)
└─B2 5 → 4 (7, 8)
└─B3 6 → 4 (9, 12)
└─C1 7 → 6 (10, 11)
└─A3 8 → 1 (14, 17)
└─B4 9 → 8 (15, 16)
First we need a table to represent the tree. And we want a tree node to have a name.
import MySQLdb as mysql
conn = mysql.connect(user = 'guest', db = 'test')
conn.query('''
CREATE TABLE `node` (
`node_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(10) unsigned DEFAULT NULL,
`l` int(10) unsigned NOT NULL,
`r` int(10) unsigned NOT NULL,
`name` varchar(8) NOT NULL,
PRIMARY KEY (`node_id`),
KEY `l` (`l`),
KEY `r` (`r`),
KEY `parent_id` (`parent_id`),
CONSTRAINT `node_has_node` FOREIGN KEY (`parent_id`)
REFERENCES `node` (`node_id`)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB;
''')
Now we can create tree instance. Note that DAO that the tree relies on is expected to support named DB-API paramstyle (i.e. WHERE node_id = :nodeId). Also transaction control methods are recommended to implement nested transaction support. However test suite requires nested transactions to run. For MySQLdb and sqlite3 there’re compatibility wrappers under fangorn.compat.
import fangorn
from fangorn.compat.mysqldb import Mysqldb as MysqldbWrapper
tree = fangorn.NestedSetsTree(MysqldbWrapper(conn), 'node', ('name',))
rId = tree.add(dict(name = 'R'))
a1Id = tree.add(dict(name = 'A1'), parentId = rId)
tree.add(dict(name = 'B1'), parentId = a1Id)
a2Id = tree.add(dict(name = 'A2'), parentId = rId)
b2Id = tree.add(dict(name = 'B2'), parentId = a2Id)
b3Id = tree.add(dict(name = 'B3'), prevId = b2Id)
tree.add(dict(name = 'C1'), parentId = b3Id)
a3Id = tree.add(dict(name = 'A3'), parentId = rId)
tree.add(dict(name = 'B4'), parentId = a3Id)
tree.move(a1Id, rId)
tree.move(a3Id, prevId = a2Id)
Now we can play with the tree.
print(tree.isDescendantOf(a2Id, 4)) # False
print(tree.isDescendantOf(a2Id, 6)) # True
print(tree.isDescendantOf(a2Id, 7)) # True
print(tree.isDescendantOf(a2Id, 9)) # False
print([n['name'] for n in tree.getChildren(a2Id)]) # ['B2', 'B3']
print([n['name'] for n in tree.getDescendants(a2Id)]) # ['B2', 'B3', 'C1']
print([n['name'] for n in tree.getPath(7)]) # ['R', 'A2', 'B3', 'C1']
print(tree.getNode(8)) # {'left': 14L, 'right': 17L, 'nodeId': 8L, 'name': 'A3', 'parentId': 1L}
print(tree.getParent(8)) # {'left': 1L, 'right': 18L, 'nodeId': 1L, 'name': 'R', 'parentId': None}
print(tree.getRoot()) # {'left': 1L, 'right': 18L, 'nodeId': 1L, 'name': 'R', 'parentId': None}
tree.edit(1, dict(name = 'RR'))
print(tree.getRoot()) # {'left': 1L, 'right': 18L, 'nodeId': 1L, 'name': 'RR', 'parentId': None}
print([n['name'] for n in tree.getDescendants(a2Id)] # ['B2', 'B3', 'C1'])
tree.remove(b3Id)
print([n['name'] for n in tree.getDescendants(a2Id)] # ['B2'])
For more usage examples look at project’s test suite.
Metadata
Release files for Fangorn 0.3.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| Fangorn-0.3.2.tar.gz | 52.6 kB | Without provenance | Details for Fangorn-0.3.2.tar.gz |
Release files / Fangorn-0.3.2.tar.gz
| Download URL | Fangorn-0.3.2.tar.gz |
|---|---|
| Size | 52.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1fe6f17b16ed36a42885ce39f0a9aa2fe2ff14f3cb91960af6843b842e536e9e
|
|
BLAKE2b-256 checksum How to use checksums |
c2cd94b08418e03542cc96d706dfdb2b5307f54a200ca56c3cf975f4555cef04
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
Security for Fangorn 0.3.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.