Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.Sign up
AttributeError: 'NoneType' object has no attribute 'seeds' #314
I've been able to create a small example to reproduce this issue. It seems to be a combination of using an Entity subclass and accessing member functions.
from pony import orm db = orm.Database('sqlite', ':memory:') class Location(db.Entity): name = orm.Optional(str) parent = orm.Optional('Location', reverse='children') children = orm.Set('Location', cascade_delete=True) orm.composite_index(name, parent) @classmethod def get_root(cls) -> 'Location': root = cls.get(name='', parent=None) if not root: root = cls(name='', parent=None) return root @classmethod def get_by_path(cls, path): current = cls.get_root() for i in range(len(path)): current = cls.get(name=path[i], parent=current) if not current: raise ValueError(path) return current @classmethod def from_path(cls, path): parent = cls.get_by_path(path[:-1]) entity = cls(name=path[-1], parent=parent) return entity def as_tuple(self): if not self.parent: return (None, self.name) return (self.parent.as_tuple(), self.name) # XXX Remove this subclass and the error does not happen. class Object(Location): pass @orm.db_session def list_location(path): # XXX Or don't use as_tuple() here. return (x.as_tuple() for x in Location.get_by_path(path).children) @orm.db_session def create_location(path): Location.from_path(path) db.generate_mapping(create_tables=True) with orm.db_session: Location.get_root() # XXX Or use this context manager. # with orm.db_session: print(list(list_location())) create_location(['com.example']) create_location(['com.example', 'foobar']) print(list(list_location(['com.example'])))
Unfortunately, none of the ways above to prevent the issue are an option in my use case. :( Any idea how to fix this?
This is the method that the AttributeError is raised in (Line 2111):
The condition above that line explicitly checks if there's any subclasses of the
Thanks for reporting!
Yes, this is correct fix. But I want to explain what is really happened:
When you work with Pony, all operations with objects should took place inside a
The last line of your test example is
In this line you execute
@orm.db_session def list_location(path): return (x.as_tuple() for x in Location.get_by_path(path).children)
In Python, generators are evaluated lazily. That is, when the function returns a generator object, it is not fully executed yet. Specifically,
At this moment Pony allows reading previously loaded attributes of objects even after
Returning to your code: I think it is better to replace generator with list comprehension. List comprehensions are evaluated eagerly, and this way we can guarantee that all evaluation will take place inside
@orm.db_session def list_location(path): return [x.as_tuple() for x in Location.get_by_path(path).children]
But after the fix I commited, previous version of code should work too