Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unpickling a tree containing a SymlinkNode causes a RecursionError #138

Closed
btwahl opened this issue Jul 12, 2020 · 2 comments
Closed

Unpickling a tree containing a SymlinkNode causes a RecursionError #138

btwahl opened this issue Jul 12, 2020 · 2 comments

Comments

@btwahl
Copy link

btwahl commented Jul 12, 2020

For context, I'm attempting to use pickle instead of the exporters provided by anytree because I have some objects that are not JSON serializable. The following is a simple example that duplicates the issue I am experiencing.

Pickling and unpickling a tree that does not contain any SymlinkNode nodes does not cause any issues and works as expected:

import pickle
from anytree import Node, SymlinkNode, RenderTree

root = Node(name='root')
a = Node(name='a', parent=root)
b = Node(name='b', parent=a)
# c = SymlinkNode(target=b, parent=a)

for pre, _, node in RenderTree(root):
    print(f'{pre}{node.name}')

with open('testtest.pkl', 'wb') as f:
    pickle.dump(root, f)

with open('testtest.pkl', 'rb') as f:
    root = pickle.load(f)

for pre, _, node in RenderTree(root):
    print(f'{pre}{node.name}')

As expected, output is:

root
└── a
    └── b
root
└── a
    └── b

However, once a SymlinkNode is introduced, there is a RecursionError:

import pickle
from anytree import Node, SymlinkNode, RenderTree

root = Node(name='root')
a = Node(name='a', parent=root)
b = Node(name='b', parent=a)
c = SymlinkNode(target=b, parent=a)

for pre, _, node in RenderTree(root):
    print(f'{pre}{node.name}')

with open('testtest.pkl', 'wb') as f:
    pickle.dump(root, f)

with open('testtest.pkl', 'rb') as f:
    root = pickle.load(f)

for pre, _, node in RenderTree(root):
    print(f'{pre}{node.name}')

Now, output is:

root
└── a
    ├── b
    └── b
Traceback (most recent call last):
  File "c:/Users/b/Documents/repos/test_space/test.py", line 18, in <module>
    root = pickle.load(f)
  File "C:\Users\b\AppData\Local\Programs\Python\Python36-32\lib\site-packages\anytree\node\symlinknodemixin.py", line 52, in __getattr__      
    return getattr(self.target, name)
  File "C:\Users\b\AppData\Local\Programs\Python\Python36-32\lib\site-packages\anytree\node\symlinknodemixin.py", line 52, in __getattr__      
    return getattr(self.target, name)
  File "C:\Users\b\AppData\Local\Programs\Python\Python36-32\lib\site-packages\anytree\node\symlinknodemixin.py", line 52, in __getattr__      
    return getattr(self.target, name)
  [Previous line repeated 329 more times]
  File "C:\Users\b\AppData\Local\Programs\Python\Python36-32\lib\site-packages\anytree\node\symlinknodemixin.py", line 49, in __getattr__
    if name in ('_NodeMixin__parent', '_NodeMixin__children'):
RecursionError: maximum recursion depth exceeded in comparison
@c0fec0de
Copy link
Owner

c0fec0de commented Jul 13, 2020 via email

@kylewhite21
Copy link
Contributor

Can be fixed by adding an elif block to the method here:

    def __getattr__(self, name):
        if name in ('_NodeMixin__parent', '_NodeMixin__children'):
            return super(SymlinkNodeMixin, self).__getattr__(name)
        elif name == '__setstate__':
            raise AttributeError(name)
        else:
            return getattr(self.target, name)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants