neo4j-contrib / neomodel

An Object Graph Mapper (OGM) for the Neo4j graph database.
https://neomodel.readthedocs.io
MIT License
967 stars 232 forks source link

__abstract_node__ does not work if applied in example from docs #523

Open p-wieland opened 4 years ago

p-wieland commented 4 years ago

Hi,

if I take the example regarding relationships and inheritance from the docs

class PersonalRelationship(neomodel.StructuredRel):
    """
    A very simple relationship between two BasePersons that simply
    records the date at which an acquaintance was established.
    """
    on_date = neomodel.DateProperty(default_now = True)

class BasePerson(neomodel.StructuredNode):
    """
    Base class for defining some basic sort of an actor in a system.

    The base actor is defined by its name and a `friends_with`
    relationship.
    """
    name = neomodel.StringProperty(required = True, unique_index = True)
    friends_with = neomodel.RelationshipTo("BasePerson", "FRIENDS_WITH", model = PersonalRelationship)

class TechnicalPerson(BasePerson):
    """
    A Technical person specialises BasePerson by adding their
    expertise.
    """
    expertise = neomodel.StringProperty(required = True)

class PilotPerson(BasePerson):
    """
    A pilot person specialises BasePerson by adding the type of
    airplane they can operate.
    """
    airplane = neomodel.StringProperty(required = True)

and add __abstract_node__ = True to the base class BasePerson and run the next code block

# Create some technical persons
A = TechnicalPerson(name = "Grumpy", expertise = "Grumpiness").save()
B = TechnicalPerson(name = "Happy", expertise = "Unicorns").save()
C = TechnicalPerson(name = "Sleepy", expertise = "Pillows").save()

# Create some Pilot Persons
D = PilotPerson(name = "Porco Rosso", airplane = "Savoia-Marchetti").save()
E = PilotPerson(name = "Jack Dalton", airplane = "Beechcraft Model 18").save()

# TechnicalPersons befriend Technical Persons
A.friends_with.connect(B)
B.friends_with.connect(C)
C.friends_with.connect(A)

# Pilot Persons befriend Pilot Persons
D.friends_with.connect(E)

# Technical Persons befriend Pilot Persons
A.friends_with.connect(D)
E.friends_with.connect(C)

for some_friend in A.friends_with:
    print(some_friend)

I get an error

Traceback (most recent call last):
  File "<input>", line 56, in <module>
  File "C:\Users\wielap\.virtualenvs\neo4j-oDySRf7e\lib\site-packages\neomodel\relationship_manager.py", line 337, in __iter__
    return self._new_traversal().__iter__()
  File "C:\Users\wielap\.virtualenvs\neo4j-oDySRf7e\lib\site-packages\neomodel\match.py", line 527, in __iter__
    return (i for i in self.query_cls(self).build_ast()._execute())
  File "C:\Users\wielap\.virtualenvs\neo4j-oDySRf7e\lib\site-packages\neomodel\match.py", line 271, in build_ast
    self.build_source(self.node_set)
  File "C:\Users\wielap\.virtualenvs\neo4j-oDySRf7e\lib\site-packages\neomodel\match.py", line 282, in build_source
    return self.build_traversal(source)
  File "C:\Users\wielap\.virtualenvs\neo4j-oDySRf7e\lib\site-packages\neomodel\match.py", line 320, in build_traversal
    rhs_label = ':' + traversal.target_class.__label__
AttributeError: type object 'BasePerson' has no attribute '__label__'

I'm using neomodel 4.0.1

googling revealed that there have been issues with abstract nodes (#234 , #262 )

na-ka-na commented 3 years ago

+1 stumbled upon this issue too and basically had to remove usage of __abstract_node__

AntonLydike commented 2 years ago

I think I stumbled upon this too, I did some light digging, and it seems that neomodel does not create labels for classes marked abstract. This then breaks some things.

Maybe it's possible to add an override to "force" add a label, even for abstract nodes? It might also be possible to automatically detect if there are edges targeting this abstract node type and include the label only then?