Skip to content

Commit f6d87a9

Browse files
Merge pull request #848 from neo4j-contrib/rc/5.4.2
Rc/5.4.2
2 parents 25b0249 + 3c7c701 commit f6d87a9

36 files changed

+1823
-991
lines changed

.github/workflows/integration-tests.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,18 @@ jobs:
3131
- name: Install dependencies
3232
run: |
3333
python -m pip install --upgrade pip
34-
pip install -e '.[dev,pandas,numpy]'
34+
pip install -e '.[dev,extras]'
3535
- name: Test with pytest
3636
env:
3737
AURA_TEST_DB_USER: ${{ secrets.AURA_TEST_DB_USER }}
3838
AURA_TEST_DB_PASSWORD: ${{ secrets.AURA_TEST_DB_PASSWORD }}
3939
AURA_TEST_DB_HOSTNAME: ${{ secrets.AURA_TEST_DB_HOSTNAME }}
4040
run: |
4141
pytest --cov=neomodel --cov-report=html:coverage_report
42+
- name: Install neo4j-rust-ext and verify it is installed
43+
run: |
44+
pip install -e '.[rust-driver-ext]'
45+
pip list | grep neo4j-rust-ext || exit 1
4246
- name: Upload coverage reports to Codecov
4347
uses: codecov/codecov-action@v3
4448
with:

Changelog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
Version 5.4.2 2024-12
2+
* Add support for Neo4j Rust driver extension : pip install neomodel[rust-driver-ext]
3+
* Add initial_context parameter to subqueries
4+
* NodeNameResolver can call self to reference top-level node
5+
* Housekeeping : implementing mypy for static typing
6+
17
Version 5.4.1 2024-11
28
* Add support for Cypher parallel runtime
39
* Add options for intermediate_transform : distinct, include_in_return, use a prop as source

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,13 @@ Install from pypi (recommended):
6565

6666
$ pip install neomodel ($ source dev # To install all things needed in a Python3 venv)
6767

68-
# Neomodel has some optional dependencies (including Shapely), to install these use:
68+
# neomodel can use the Rust extension to the Neo4j driver for faster transport, to install use:
6969

70-
$ pip install neomodel['extras']
70+
$ pip install neomodel[rust-driver-ext]
71+
72+
# neomodel has some optional dependencies (Shapely, pandas, numpy), to install these use:
73+
74+
$ pip install neomodel[extras, rust-driver-ext]
7175

7276
To install from github:
7377

doc/source/advanced_query_operations.rst

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ As discussed in the note above, this is for example useful when you need to orde
6060

6161
Options for `intermediate_transform` *variables* are:
6262

63-
- `source`: `string`or `Resolver` - the variable to use as source for the transformation. Works with resolvers (see below).
63+
- `source`: `string` or `Resolver` - the variable to use as source for the transformation. Works with resolvers (see below).
6464
- `source_prop`: `string` - optionally, a property of the source variable to use as source for the transformation.
6565
- `include_in_return`: `bool` - whether to include the variable in the return statement. Defaults to False.
6666

@@ -95,7 +95,7 @@ Subqueries
9595
The `subquery` method allows you to perform a `Cypher subquery <https://neo4j.com/docs/cypher-manual/current/subqueries/call-subquery/>`_ inside your query. This allows you to perform operations in isolation to the rest of your query::
9696

9797
from neomodel.sync_match import Collect, Last
98-
98+
9999
# This will create a CALL{} subquery
100100
# And return a variable named supps usable in the rest of your query
101101
Coffee.nodes.filter(name="Espresso")
@@ -106,12 +106,18 @@ The `subquery` method allows you to perform a `Cypher subquery <https://neo4j.co
106106
)
107107
.annotate(supps=Last(Collect("suppliers"))),
108108
["supps"],
109+
[NodeNameResolver("self")]
109110
)
110111

112+
Options for `subquery` calls are:
113+
114+
- `return_set`: list of `string` - the subquery variables that should be included in the outer query result
115+
- `initial_context`: optional list of `string` or `Resolver` - the outer query variables that will be injected at the begining of the subquery
116+
111117
.. note::
112-
Notice the subquery starts with Coffee.nodes ; neomodel will use this to know it needs to inject the source "coffee" variable generated by the outer query into the subquery. This means only Espresso coffee nodes will be considered in the subquery.
118+
In the example above, we reference `self` to be included in the initial context. It will actually inject the outer variable corresponding to `Coffee` node.
113119

114-
We know this is confusing to read, but have not found a better wat to do this yet. If you have any suggestions, please let us know.
120+
We know this is confusing to read, but have not found a better way to do this yet. If you have any suggestions, please let us know.
115121

116122
Helpers
117123
-------

doc/source/configuration.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Adjust driver configuration - these options are only available for this connecti
3232
config.MAX_TRANSACTION_RETRY_TIME = 30.0 # default
3333
config.RESOLVER = None # default
3434
config.TRUST = neo4j.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES # default
35-
config.USER_AGENT = neomodel/v5.4.1 # default
35+
config.USER_AGENT = neomodel/v5.4.2 # default
3636

3737
Setting the database name, if different from the default one::
3838

neomodel/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "5.4.1"
1+
__version__ = "5.4.2"

neomodel/async_/cardinality.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
1+
from typing import TYPE_CHECKING, Any, Optional
2+
13
from neomodel.async_.relationship_manager import ( # pylint:disable=unused-import
24
AsyncRelationshipManager,
35
AsyncZeroOrMore,
46
)
57
from neomodel.exceptions import AttemptedCardinalityViolation, CardinalityViolation
68

9+
if TYPE_CHECKING:
10+
from neomodel import AsyncStructuredNode, AsyncStructuredRel
11+
712

813
class AsyncZeroOrOne(AsyncRelationshipManager):
914
"""A relationship to zero or one node."""
1015

1116
description = "zero or one relationship"
1217

13-
async def single(self):
18+
async def single(self) -> Optional["AsyncStructuredNode"]:
1419
"""
1520
Return the associated node.
1621
@@ -23,11 +28,13 @@ async def single(self):
2328
raise CardinalityViolation(self, len(nodes))
2429
return None
2530

26-
async def all(self):
31+
async def all(self) -> list["AsyncStructuredNode"]:
2732
node = await self.single()
2833
return [node] if node else []
2934

30-
async def connect(self, node, properties=None):
35+
async def connect(
36+
self, node: "AsyncStructuredNode", properties: Optional[dict[str, Any]] = None
37+
) -> "AsyncStructuredRel":
3138
"""
3239
Connect to a node.
3340
@@ -49,7 +56,7 @@ class AsyncOneOrMore(AsyncRelationshipManager):
4956

5057
description = "one or more relationships"
5158

52-
async def single(self):
59+
async def single(self) -> "AsyncStructuredNode":
5360
"""
5461
Fetch one of the related nodes
5562
@@ -60,7 +67,7 @@ async def single(self):
6067
return nodes[0]
6168
raise CardinalityViolation(self, "none")
6269

63-
async def all(self):
70+
async def all(self) -> list["AsyncStructuredNode"]:
6471
"""
6572
Returns all related nodes.
6673
@@ -71,7 +78,7 @@ async def all(self):
7178
return nodes
7279
raise CardinalityViolation(self, "none")
7380

74-
async def disconnect(self, node):
81+
async def disconnect(self, node: "AsyncStructuredNode") -> None:
7582
"""
7683
Disconnect node
7784
:param node:
@@ -89,7 +96,7 @@ class AsyncOne(AsyncRelationshipManager):
8996

9097
description = "one relationship"
9198

92-
async def single(self):
99+
async def single(self) -> "AsyncStructuredNode":
93100
"""
94101
Return the associated node.
95102
@@ -102,25 +109,27 @@ async def single(self):
102109
raise CardinalityViolation(self, len(nodes))
103110
raise CardinalityViolation(self, "none")
104111

105-
async def all(self):
112+
async def all(self) -> list["AsyncStructuredNode"]:
106113
"""
107114
Return single node in an array
108115
109116
:return: [node]
110117
"""
111118
return [await self.single()]
112119

113-
async def disconnect(self, node):
120+
async def disconnect(self, node: "AsyncStructuredNode") -> None:
114121
raise AttemptedCardinalityViolation(
115122
"Cardinality one, cannot disconnect use reconnect."
116123
)
117124

118-
async def disconnect_all(self):
125+
async def disconnect_all(self) -> None:
119126
raise AttemptedCardinalityViolation(
120127
"Cardinality one, cannot disconnect_all use reconnect."
121128
)
122129

123-
async def connect(self, node, properties=None):
130+
async def connect(
131+
self, node: "AsyncStructuredNode", properties: Optional[dict[str, Any]] = None
132+
) -> "AsyncStructuredRel":
124133
"""
125134
Connect a node
126135

0 commit comments

Comments
 (0)