From a9d55a0d61eb84e63cf2079d920add79ff1fef98 Mon Sep 17 00:00:00 2001
From: mprahl <mprahl@users.noreply.github.com>
Date: Thu, 14 Jun 2018 09:48:37 -0400
Subject: [PATCH] Support neo4j-driver v1.6.0
As part of neo4j-driver v1.6.0, `properties` was renamed to
`_properties` on `neo4j.v1.types.graph.Node`. This commit addresses
that and changes the version restriction in setup.py to allow
neo4j-driver 1.6.0.
---
neomodel/contrib/semi_structured.py | 12 +++++++-----
neomodel/core.py | 7 ++++---
neomodel/relationship_manager.py | 5 +++--
neomodel/util.py | 10 ++++++++++
setup.py | 2 +-
test/test_properties.py | 14 ++++++++------
6 files changed, 33 insertions(+), 17 deletions(-)
diff --git a/neomodel/contrib/semi_structured.py b/neomodel/contrib/semi_structured.py
index 20c25b6..883a589 100644
--- a/neomodel/contrib/semi_structured.py
+++ b/neomodel/contrib/semi_structured.py
@@ -1,5 +1,6 @@
from neomodel.core import StructuredNode
from neomodel.exceptions import InflateConflict, DeflateConflict
+from neomodel.util import _get_node_properties
class SemiStructuredNode(StructuredNode):
@@ -33,18 +34,19 @@ def inflate(cls, node):
else:
props = {}
for key, prop in cls.__all_properties__:
- if key in node.properties:
- props[key] = prop.inflate(node.properties[key], node)
+ node_properties = _get_node_properties(node)
+ if key in node_properties:
+ props[key] = prop.inflate(node_properties[key], node)
elif prop.has_default:
props[key] = prop.default_value()
else:
props[key] = None
# handle properties not defined on the class
- for free_key in (x for x in node.properties if x not in props):
+ for free_key in (x for x in node_properties if x not in props):
if hasattr(cls, free_key):
raise InflateConflict(cls, free_key,
- node.properties[free_key], node.id)
- props[free_key] = node.properties[free_key]
+ node_properties[free_key], node.id)
+ props[free_key] = node_properties[free_key]
snode = cls(**props)
snode.id = node.id
diff --git a/neomodel/core.py b/neomodel/core.py
index 5d56e28..65d6e48 100644
--- a/neomodel/core.py
+++ b/neomodel/core.py
@@ -6,7 +6,7 @@
from neomodel.exceptions import DoesNotExist
from neomodel.hooks import hooks
from neomodel.properties import Property, PropertyManager
-from neomodel.util import Database, classproperty, _UnsavedNode
+from neomodel.util import Database, classproperty, _UnsavedNode, _get_node_properties
db = Database()
@@ -438,13 +438,14 @@ def inflate(cls, node):
snode = cls()
snode.id = node
else:
+ node_properties = _get_node_properties(node)
props = {}
for key, prop in cls.__all_properties__:
# map property name from database to object property
db_property = prop.db_property or key
- if db_property in node.properties:
- props[key] = prop.inflate(node.properties[db_property], node)
+ if db_property in node_properties:
+ props[key] = prop.inflate(node_properties[db_property], node)
elif prop.has_default:
props[key] = prop.default_value()
else:
diff --git a/neomodel/relationship_manager.py b/neomodel/relationship_manager.py
index 0563aeb..cc027b6 100644
--- a/neomodel/relationship_manager.py
+++ b/neomodel/relationship_manager.py
@@ -2,7 +2,7 @@
import functools
from importlib import import_module
from .exceptions import NotConnected
-from .util import deprecated
+from .util import deprecated, _get_node_properties
from .match import OUTGOING, INCOMING, EITHER, _rel_helper, Traversal, NodeSet
from .relationship import StructuredRel
@@ -190,7 +190,8 @@ def reconnect(self, old_node, new_node):
"MATCH (us), (old) WHERE id(us)={self} and id(old)={old} "
"MATCH " + old_rel + " RETURN r", {'old': old_node.id})
if result:
- existing_properties = result[0][0].properties.keys()
+ node_properties = _get_node_properties(result[0][0])
+ existing_properties = node_properties.keys()
else:
raise NotConnected('reconnect', self.source, old_node)
diff --git a/neomodel/util.py b/neomodel/util.py
index bad14ff..d175688 100644
--- a/neomodel/util.py
+++ b/neomodel/util.py
@@ -193,3 +193,13 @@ def __repr__(self):
def __str__(self):
return self.__repr__()
+
+
+def _get_node_properties(node):
+ """Get the properties from a neo4j.v1.types.graph.Node object."""
+ # 1.6.x and newer have it as `_properties`
+ if hasattr(node, '_properties'):
+ return node._properties
+ # 1.5.x and older have it as `properties`
+ else:
+ return node.properties
diff --git a/setup.py b/setup.py
index 889fe46..1943d83 100644
--- a/setup.py
+++ b/setup.py
@@ -17,7 +17,7 @@
scripts=['scripts/neomodel_install_labels', 'scripts/neomodel_remove_labels'],
setup_requires=['pytest-runner'] if any(x in ('pytest', 'test') for x in sys.argv) else [],
tests_require=['pytest'],
- install_requires=['neo4j-driver==1.5.2', 'pytz>=2016.10'],
+ install_requires=['neo4j-driver>=1.5.2, <1.7.0', 'pytz>=2016.10'],
classifiers=[
"Development Status :: 5 - Production/Stable",
'Intended Audience :: Developers',
diff --git a/test/test_properties.py b/test/test_properties.py
index 0b85ebd..368caf8 100644
--- a/test/test_properties.py
+++ b/test/test_properties.py
@@ -10,8 +10,7 @@
EmailProperty, JSONProperty, NormalProperty, NormalizedProperty,
RegexProperty, StringProperty, UniqueIdProperty
)
-
-
+from neomodel.util import _get_node_properties
class FooBar(object):
@@ -187,9 +186,11 @@ class TestNode(StructuredNode):
# check database property name on low level
results, meta = db.cypher_query("MATCH (n:TestNode) RETURN n")
- assert results[0][0].properties['name'] == "jim"
+ node_properties = _get_node_properties(results[0][0])
+ assert node_properties['name'] == "jim"
- assert not 'name_' in results[0][0].properties
+ node_properties = _get_node_properties(results[0][0])
+ assert not 'name_' in node_properties
assert not hasattr(x, 'name')
assert hasattr(x, 'name_')
assert TestNode.nodes.filter(name_="jim").all()[0].name_ == x.name_
@@ -210,8 +211,9 @@ class TestNode(StructuredNode):
# check database property name on low level
results, meta = db.cypher_query("MATCH (n:TestNode) RETURN n")
- assert results[0][0].properties['name'] == "jim"
- assert 'name_' not in results[0][0].properties
+ node_properties = _get_node_properties(results[0][0])
+ assert node_properties['name'] == "jim"
+ assert 'name_' not in node_properties
# delete node afterwards
x.delete()