neo4j-contrib/neomodel

'module' object has no attribute 'Person'

fredthedead opened this issue · 7 comments

I'm trying the basic example from the docs and it's failing on this command germany = Country(code='DE').save() returning 'module' object has no attribute 'Person'

This is either an issue with the docs (which after re-reading them I still can't figure what's wrong) or with the package...

What's wrong?

(btw the Person/Jim node is create successfully...)

Thank you, will have a quick look at this but in the meantime, would it be possible to post the exact snippet you are working on?

Hello again. Two things about this:

  1. I cannot see any functional problem with that part of the code. What I tested was creating a Country, a Person and connecting the two. It would be worth elaborating If you are coming across this error after a specific sequence of operations (?).

  2. As a more general tip however, I would avoid this kind of reciprocal connectivity with RelationshipTo, RelationshipFrom. This is a short and simple example to demonstrate the neomodel functionality but if you want to establish a relationship and it is supposed to be traversable in both directions, then establish a Relationship and then provide a hint about the direction it should be traversed in a query via CYPHER.

Hope this helps.

Many thanks for the quick reply

I switched to Relationship in both classes and getting the same error. Given that it works for you I guess it is something in my setup (I'm using the Neo4j 3.5.3 community docker image via ngrok, and tried two versions of Neomodel: 3.2.9 & 3.3.1

The full snippet is:

from neomodel import (config, StructuredNode, StringProperty, IntegerProperty,
    UniqueIdProperty, RelationshipTo, RelationshipFrom, Relationship)

config.DATABASE_URL = 'bolt://:@host:port'

class Country(StructuredNode):
    code = StringProperty(unique_index=True, required=True)
    inhabitant = Relationship('Person', 'IS_FROM')

class Person(StructuredNode):
    uid = UniqueIdProperty()
    name = StringProperty(unique_index=True)
    age = IntegerProperty(index=True, default=0)
    country = Relationship(Country, 'IS_FROM')

jim = Person(name='Jim', age=3).save()

germany = Country(code='DE').save() <--- the line that fails and returns the error

@fredthedead No worries.

The point about the relationship note from above is about discouraging reciprocal relationships. The way this is modelled (in the revised version) establishes one undirected relationship from Country to Person and another from Person to Country. So, not much of an improvement I am afraid.

To an extent, what you are describing here could be part of an improvement in the way neomodel manages relationships at a higher level.

But, on where we are now:

  1. Try to establish just one Relationship of type IS_FROM. At the moment, the relationship will appear as an attribute on the neomodel entity it is defined in only.

  2. This simply means that you would not be able to perform From traversals from the "other" entity using the high level neomodel facilities for querying (node sets, etc). You might find this cumbersome depending on what you are trying to do, but it is still doable using neomodel with some reasonable adjustments.

  3. Establishing just one Relationship at the model level still means that the IS_FROM relationship will be established in the database as expected (one undirected relationship between two nodes) which means that you would still be able to traverse it via a node's cypher or neomodel.db's cypher_query.

  4. A node's query and neomodel.db.cypher_query functions can return properly instantiated objects, so from the point of view of READ operations, this is not a huge limitation.

  5. I will try replicating that error locally but I am not sure how quickly I will be able to do that. Are there any additional logs from neo4j or the full exception trace that might be revealing a bit more information about what is wrong?

Hope this helps.

Thanks again, removing the relationship from one of the classes works and the two nodes get linked. As you've guessed, the reason I wanted to have the relationship in both entities is for the ease of querying. I'll try to achieve that using cypher as you suggested.

Here's the full exception trace, apologies for not including it earlier:

AttributeError                            Traceback (most recent call last)
<command-25674> in <module>()
----> 1 germany = Country(code='DE').save()

/local_disk0/pythonVirtualEnvDirs/virtualEnv/local/lib/python2.7/site-packages/neomodel/core.pyc in __init__(self, *args, **kwargs)
    204 
    205         for key, val in self.__all_relationships__:
--> 206             self.__dict__[key] = val.build_manager(self, key)
    207 
    208         super(StructuredNode, self).__init__(*args, **kwargs)

/local_disk0/pythonVirtualEnvDirs/virtualEnv/local/lib/python2.7/site-packages/neomodel/relationship_manager.pyc in build_manager(self, source, name)
    400 
    401     def build_manager(self, source, name):
--> 402         self._lookup_node_class()
    403         return self.manager(source, name, self.definition)
    404 

/local_disk0/pythonVirtualEnvDirs/virtualEnv/local/lib/python2.7/site-packages/neomodel/relationship_manager.pyc in _lookup_node_class(self)
    397                 else:
    398                     module = import_module(namespace).__name__
--> 399             self.definition['node_class'] = getattr(sys.modules[module], name)
    400 
    401     def build_manager(self, source, name):

AttributeError: 'module' object has no attribute 'Person'

I'm not able to inspect any of these values further since it's running in a notebook environment that doesn't support that.

I dug deeper into this, I suspect this is something related to the code being ran in a notebook... it looks like the node classes belong to the __main__ module (that's what I get when I run inspect.getmodule(Person) -> <module '__main__' from '/local_disk0/tmp/PythonShell.py'>) but they are not listed when calling sys.modules[module_name]

@fredthedead No worries.

This trace indicates a problem during the .save() operation itself indeed.

In my setup, I tried a Jupyter notebook and:

  1. Could not connect to a Python3 kernel

    • Switched to a Python 2 based notebook
  2. Tried to create a simple StructuredNode and use it to write to the database

    • Crashed the neo4j server

But finally got 2 working by stepping through the cells manually, making sure I leave a bit of time between evaluations.

Not really sure if this is something to do with the way the cells are evaluated internally by Jupyter, but perhaps the order of execution does matter here.

Can you please try running the cells one by one and manually (to ensure that the series of operations is preserved) and let me know if that worked for you?