-
Notifications
You must be signed in to change notification settings - Fork 220
Description
Context
We are working on a project using treebeard's NS_Node implementation. We are building a system to recursively copy a folder structure into our database for tracking.
Issue
We found that recursively calling add_child
resulted in an invalid tree data structure, with problems such as a child with multiple parents. After some digging, we discovered that this error was the result of a caching problem in add_child
. We were able to implement a workaround for this bug by calling refresh_from_db()
on the parent node
before calling node.add_child()
.
We additionally attempted using the load_bulk
function to see if this was an undocumented difference between add_child
and load_bulk
and found that this is a breaking bug for this function. load_bulk
errors with
AttributeError: 'NoneType' object has no attribute '_cached_parent_obj'
Reproducible Example of load_bulk
To recreate the load_bulk
issue on a model Folder(NS_Node)
:
new_root = Folder.add_root(name="new_root")
a_id = uuid.uuid4()
b_id = uuid.uuid4()
Folder.load_bulk([{"data": {"name": "a"}, "id": a_id, "children": [{"data": {"name": "b"}, "id": b_id}]}], new_root, True)
Reproducible Example of add_child
Given file structure:
A
- B
- C
- File 1
We would expect to have three folders; A
, children B
and C
. File 1
would be within Folder C
. Instead, we see that C.get_parent()
is B
. Our implementation (with the workaround) is below:
def create_folders_and_files(tree, parent):
parent.refresh_from_db() # THIS IS THE WORKAROUND
new_folder = parent.add_child(name=tree['name'])
for file, full_name in tree['files']:
# create file within the folder you just made
for folder in tree['folders']:
create_folders_and_files(folder, new_folder)
create_folders_and_files(tree, root_node)