Skip to content

Commit b273101

Browse files
authored
Fix missed renamings from x_transaction to execute_x (#786)
Amends #784 There were other mentions/usages of `Session.read/write_transaction` that needed replacing with `Session.execute_read/write`. While there was a test to make sure the example in the README works, there was no assertion the test actually tests what's in the README. Added a test to assert the former test resembles the README example.
1 parent 212cfd4 commit b273101

File tree

7 files changed

+116
-35
lines changed

7 files changed

+116
-35
lines changed

README.rst

+9-7
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,25 @@ Quick Example
3131
3232
from neo4j import GraphDatabase
3333
34-
driver = GraphDatabase.driver("neo4j://localhost:7687", auth=("neo4j", "password"))
34+
driver = GraphDatabase.driver("neo4j://localhost:7687",
35+
auth=("neo4j", "password"))
3536
3637
def add_friend(tx, name, friend_name):
3738
tx.run("MERGE (a:Person {name: $name}) "
3839
"MERGE (a)-[:KNOWS]->(friend:Person {name: $friend_name})",
3940
name=name, friend_name=friend_name)
4041
4142
def print_friends(tx, name):
42-
for record in tx.run("MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
43-
"RETURN friend.name ORDER BY friend.name", name=name):
43+
query = ("MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
44+
"RETURN friend.name ORDER BY friend.name")
45+
for record in tx.run(query, name=name):
4446
print(record["friend.name"])
4547
4648
with driver.session() as session:
47-
session.write_transaction(add_friend, "Arthur", "Guinevere")
48-
session.write_transaction(add_friend, "Arthur", "Lancelot")
49-
session.write_transaction(add_friend, "Arthur", "Merlin")
50-
session.read_transaction(print_friends, "Arthur")
49+
session.execute_write(add_friend, "Arthur", "Guinevere")
50+
session.execute_write(add_friend, "Arthur", "Lancelot")
51+
session.execute_write(add_friend, "Arthur", "Merlin")
52+
session.execute_read(print_friends, "Arthur")
5153
5254
driver.close()
5355

docs/source/api.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -849,8 +849,8 @@ Managed Transactions (`transaction functions`)
849849
==============================================
850850
Transaction functions are the most powerful form of transaction, providing access mode override and retry capabilities.
851851

852-
+ :meth:`neo4j.Session.write_transaction`
853-
+ :meth:`neo4j.Session.read_transaction`
852+
+ :meth:`neo4j.Session.execute_write`
853+
+ :meth:`neo4j.Session.execute_read`
854854

855855
These allow a function object representing the transactional unit of work to be passed as a parameter.
856856
This function is called one or more times, within a configurable time limit, until it succeeds.
@@ -869,7 +869,7 @@ Example:
869869
870870
def create_person(driver, name)
871871
with driver.session() as session:
872-
node_id = session.write_transaction(create_person_tx, name)
872+
node_id = session.execute_write(create_person_tx, name)
873873
874874
def create_person_tx(tx, name):
875875
query = "CREATE (a:Person { name: $name }) RETURN id(a) AS node_id"

docs/source/async_api.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -522,8 +522,8 @@ Managed Async Transactions (`transaction functions`)
522522
====================================================
523523
Transaction functions are the most powerful form of transaction, providing access mode override and retry capabilities.
524524

525-
+ :meth:`neo4j.AsyncSession.write_transaction`
526-
+ :meth:`neo4j.AsyncSession.read_transaction`
525+
+ :meth:`neo4j.AsyncSession.execute_write`
526+
+ :meth:`neo4j.AsyncSession.execute_read`
527527

528528
These allow a function object representing the transactional unit of work to be passed as a parameter.
529529
This function is called one or more times, within a configurable time limit, until it succeeds.
@@ -542,7 +542,7 @@ Example:
542542
543543
async def create_person(driver, name)
544544
async with driver.session() as session:
545-
node_id = await session.write_transaction(create_person_tx, name)
545+
node_id = await session.execute_write(create_person_tx, name)
546546
547547
async def create_person_tx(tx, name):
548548
query = "CREATE (a:Person { name: $name }) RETURN id(a) AS node_id"

docs/source/index.rst

+6-6
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@ Creating nodes and relationships.
109109
name=name, friend=friend)
110110
111111
with driver.session() as session:
112-
session.write_transaction(create_person, "Alice")
113-
session.write_transaction(create_friend_of, "Alice", "Bob")
114-
session.write_transaction(create_friend_of, "Alice", "Carl")
112+
session.execute_write(create_person, "Alice")
113+
session.execute_write(create_friend_of, "Alice", "Bob")
114+
session.execute_write(create_friend_of, "Alice", "Carl")
115115
116116
driver.close()
117117
@@ -135,7 +135,7 @@ Finding nodes.
135135
return friends
136136
137137
with driver.session() as session:
138-
friends = session.read_transaction(get_friends_of, "Alice")
138+
friends = session.execute_read(get_friends_of, "Alice")
139139
for friend in friends:
140140
print(friend)
141141
@@ -164,7 +164,7 @@ Example Application
164164
def create_friendship(self, person1_name, person2_name):
165165
with self.driver.session() as session:
166166
# Write transactions allow the driver to handle retries and transient errors
167-
result = session.write_transaction(
167+
result = session.execute_write(
168168
self._create_and_return_friendship, person1_name, person2_name)
169169
for record in result:
170170
print("Created friendship between: {p1}, {p2}".format(
@@ -197,7 +197,7 @@ Example Application
197197
198198
def find_person(self, person_name):
199199
with self.driver.session() as session:
200-
result = session.read_transaction(self._find_and_return_person, person_name)
200+
result = session.execute_read(self._find_and_return_person, person_name)
201201
for record in result:
202202
print("Found person: {record}".format(record=record))
203203

tests/integration/test_readme.py

+39-8
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
# limitations under the License.
1717

1818

19-
import pytest
20-
21-
from neo4j.exceptions import ServiceUnavailable
19+
from pathlib import Path
2220

2321

2422
# python -m pytest tests/integration/test_readme.py -s -v
@@ -28,30 +26,63 @@ def test_should_run_readme(uri, auth):
2826
names = set()
2927
print = names.add
3028

29+
# === START: README ===
3130
from neo4j import GraphDatabase
3231

32+
driver = GraphDatabase.driver("neo4j://localhost:7687",
33+
auth=("neo4j", "password"))
34+
# === END: README ===
3335
driver = GraphDatabase.driver(uri, auth=auth)
36+
# === START: README ===
3437

3538
def add_friend(tx, name, friend_name):
3639
tx.run("MERGE (a:Person {name: $name}) "
3740
"MERGE (a)-[:KNOWS]->(friend:Person {name: $friend_name})",
3841
name=name, friend_name=friend_name)
3942

4043
def print_friends(tx, name):
41-
for record in tx.run(
42-
"MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
43-
"RETURN friend.name ORDER BY friend.name", name=name):
44+
query = ("MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
45+
"RETURN friend.name ORDER BY friend.name")
46+
for record in tx.run(query, name=name):
4447
print(record["friend.name"])
4548

4649
with driver.session() as session:
50+
# === END: README ===
4751
session.run("MATCH (a) DETACH DELETE a")
48-
52+
# === START: README ===
4953
session.execute_write(add_friend, "Arthur", "Guinevere")
5054
session.execute_write(add_friend, "Arthur", "Lancelot")
5155
session.execute_write(add_friend, "Arthur", "Merlin")
5256
session.execute_read(print_friends, "Arthur")
53-
57+
# === END: README ===
5458
session.run("MATCH (a) DETACH DELETE a")
59+
# === START: README ===
5560

5661
driver.close()
62+
# === END: README ===
5763
assert names == {"Guinevere", "Lancelot", "Merlin"}
64+
65+
66+
def test_readme_contains_example():
67+
test_path = Path(__file__)
68+
readme_path = test_path.parents[2] / "README.rst"
69+
70+
with test_path.open("r") as fd:
71+
test_content = fd.read()
72+
with readme_path.open("r") as fd:
73+
readme_content = fd.read()
74+
75+
stripped_test_content = ""
76+
77+
adding = False
78+
for line in test_content.splitlines(keepends=True):
79+
if line.strip() == "# === START: README ===":
80+
adding = True
81+
continue
82+
elif line.strip() == "# === END: README ===":
83+
adding = False
84+
continue
85+
if adding:
86+
stripped_test_content += line
87+
88+
assert stripped_test_content in readme_content

tests/unit/async_/work/test_session.py

+28-4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@
3737
from ...._async_compat import mark_async_test
3838

3939

40+
@contextmanager
41+
def assert_warns_tx_func_deprecation(tx_func_name):
42+
if tx_func_name.endswith("_transaction"):
43+
with pytest.warns(DeprecationWarning,
44+
match=f"{tx_func_name}.*execute_"):
45+
yield
46+
else:
47+
yield
48+
49+
4050
@mark_async_test
4151
async def test_session_context_calls_close(mocker):
4252
s = AsyncSession(None, SessionConfig())
@@ -237,17 +247,25 @@ async def test_session_run_wrong_types(fake_pool, query, error_type):
237247
await session.run(query)
238248

239249

240-
@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction"))
250+
@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction",
251+
"execute_write", "execute_read",))
241252
@mark_async_test
242253
async def test_tx_function_argument_type(fake_pool, tx_type):
254+
called = False
255+
243256
async def work(tx):
257+
nonlocal called
258+
called = True
244259
assert isinstance(tx, AsyncManagedTransaction)
245260

246261
async with AsyncSession(fake_pool, SessionConfig()) as session:
247-
await getattr(session, tx_type)(work)
262+
with assert_warns_tx_func_deprecation(tx_type):
263+
await getattr(session, tx_type)(work)
264+
assert called
248265

249266

250-
@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction"))
267+
@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction",
268+
"execute_write", "execute_read"))
251269
@pytest.mark.parametrize("decorator_kwargs", (
252270
{},
253271
{"timeout": 5},
@@ -259,12 +277,18 @@ async def work(tx):
259277
async def test_decorated_tx_function_argument_type(
260278
fake_pool, tx_type, decorator_kwargs
261279
):
280+
called = False
281+
262282
@unit_of_work(**decorator_kwargs)
263283
async def work(tx):
284+
nonlocal called
285+
called = True
264286
assert isinstance(tx, AsyncManagedTransaction)
265287

266288
async with AsyncSession(fake_pool, SessionConfig()) as session:
267-
await getattr(session, tx_type)(work)
289+
with assert_warns_tx_func_deprecation(tx_type):
290+
await getattr(session, tx_type)(work)
291+
assert called
268292

269293

270294
@mark_async_test

tests/unit/sync/work/test_session.py

+28-4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@
3737
from ...._async_compat import mark_sync_test
3838

3939

40+
@contextmanager
41+
def assert_warns_tx_func_deprecation(tx_func_name):
42+
if tx_func_name.endswith("_transaction"):
43+
with pytest.warns(DeprecationWarning,
44+
match=f"{tx_func_name}.*execute_"):
45+
yield
46+
else:
47+
yield
48+
49+
4050
@mark_sync_test
4151
def test_session_context_calls_close(mocker):
4252
s = Session(None, SessionConfig())
@@ -237,17 +247,25 @@ def test_session_run_wrong_types(fake_pool, query, error_type):
237247
session.run(query)
238248

239249

240-
@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction"))
250+
@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction",
251+
"execute_write", "execute_read",))
241252
@mark_sync_test
242253
def test_tx_function_argument_type(fake_pool, tx_type):
254+
called = False
255+
243256
def work(tx):
257+
nonlocal called
258+
called = True
244259
assert isinstance(tx, ManagedTransaction)
245260

246261
with Session(fake_pool, SessionConfig()) as session:
247-
getattr(session, tx_type)(work)
262+
with assert_warns_tx_func_deprecation(tx_type):
263+
getattr(session, tx_type)(work)
264+
assert called
248265

249266

250-
@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction"))
267+
@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction",
268+
"execute_write", "execute_read"))
251269
@pytest.mark.parametrize("decorator_kwargs", (
252270
{},
253271
{"timeout": 5},
@@ -259,12 +277,18 @@ def work(tx):
259277
def test_decorated_tx_function_argument_type(
260278
fake_pool, tx_type, decorator_kwargs
261279
):
280+
called = False
281+
262282
@unit_of_work(**decorator_kwargs)
263283
def work(tx):
284+
nonlocal called
285+
called = True
264286
assert isinstance(tx, ManagedTransaction)
265287

266288
with Session(fake_pool, SessionConfig()) as session:
267-
getattr(session, tx_type)(work)
289+
with assert_warns_tx_func_deprecation(tx_type):
290+
getattr(session, tx_type)(work)
291+
assert called
268292

269293

270294
@mark_sync_test

0 commit comments

Comments
 (0)