Skip to content

Fix missed renamings from x_transaction to execute_x #786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,25 @@ Quick Example

from neo4j import GraphDatabase

driver = GraphDatabase.driver("neo4j://localhost:7687", auth=("neo4j", "password"))
driver = GraphDatabase.driver("neo4j://localhost:7687",
auth=("neo4j", "password"))

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

def print_friends(tx, name):
for record in tx.run("MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
"RETURN friend.name ORDER BY friend.name", name=name):
query = ("MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
"RETURN friend.name ORDER BY friend.name")
for record in tx.run(query, name=name):
print(record["friend.name"])

with driver.session() as session:
session.write_transaction(add_friend, "Arthur", "Guinevere")
session.write_transaction(add_friend, "Arthur", "Lancelot")
session.write_transaction(add_friend, "Arthur", "Merlin")
session.read_transaction(print_friends, "Arthur")
session.execute_write(add_friend, "Arthur", "Guinevere")
session.execute_write(add_friend, "Arthur", "Lancelot")
session.execute_write(add_friend, "Arthur", "Merlin")
session.execute_read(print_friends, "Arthur")

driver.close()

Expand Down
6 changes: 3 additions & 3 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -849,8 +849,8 @@ Managed Transactions (`transaction functions`)
==============================================
Transaction functions are the most powerful form of transaction, providing access mode override and retry capabilities.

+ :meth:`neo4j.Session.write_transaction`
+ :meth:`neo4j.Session.read_transaction`
+ :meth:`neo4j.Session.execute_write`
+ :meth:`neo4j.Session.execute_read`

These allow a function object representing the transactional unit of work to be passed as a parameter.
This function is called one or more times, within a configurable time limit, until it succeeds.
Expand All @@ -869,7 +869,7 @@ Example:

def create_person(driver, name)
with driver.session() as session:
node_id = session.write_transaction(create_person_tx, name)
node_id = session.execute_write(create_person_tx, name)

def create_person_tx(tx, name):
query = "CREATE (a:Person { name: $name }) RETURN id(a) AS node_id"
Expand Down
6 changes: 3 additions & 3 deletions docs/source/async_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -522,8 +522,8 @@ Managed Async Transactions (`transaction functions`)
====================================================
Transaction functions are the most powerful form of transaction, providing access mode override and retry capabilities.

+ :meth:`neo4j.AsyncSession.write_transaction`
+ :meth:`neo4j.AsyncSession.read_transaction`
+ :meth:`neo4j.AsyncSession.execute_write`
+ :meth:`neo4j.AsyncSession.execute_read`

These allow a function object representing the transactional unit of work to be passed as a parameter.
This function is called one or more times, within a configurable time limit, until it succeeds.
Expand All @@ -542,7 +542,7 @@ Example:

async def create_person(driver, name)
async with driver.session() as session:
node_id = await session.write_transaction(create_person_tx, name)
node_id = await session.execute_write(create_person_tx, name)

async def create_person_tx(tx, name):
query = "CREATE (a:Person { name: $name }) RETURN id(a) AS node_id"
Expand Down
12 changes: 6 additions & 6 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ Creating nodes and relationships.
name=name, friend=friend)

with driver.session() as session:
session.write_transaction(create_person, "Alice")
session.write_transaction(create_friend_of, "Alice", "Bob")
session.write_transaction(create_friend_of, "Alice", "Carl")
session.execute_write(create_person, "Alice")
session.execute_write(create_friend_of, "Alice", "Bob")
session.execute_write(create_friend_of, "Alice", "Carl")

driver.close()

Expand All @@ -135,7 +135,7 @@ Finding nodes.
return friends

with driver.session() as session:
friends = session.read_transaction(get_friends_of, "Alice")
friends = session.execute_read(get_friends_of, "Alice")
for friend in friends:
print(friend)

Expand Down Expand Up @@ -164,7 +164,7 @@ Example Application
def create_friendship(self, person1_name, person2_name):
with self.driver.session() as session:
# Write transactions allow the driver to handle retries and transient errors
result = session.write_transaction(
result = session.execute_write(
self._create_and_return_friendship, person1_name, person2_name)
for record in result:
print("Created friendship between: {p1}, {p2}".format(
Expand Down Expand Up @@ -197,7 +197,7 @@ Example Application

def find_person(self, person_name):
with self.driver.session() as session:
result = session.read_transaction(self._find_and_return_person, person_name)
result = session.execute_read(self._find_and_return_person, person_name)
for record in result:
print("Found person: {record}".format(record=record))

Expand Down
47 changes: 39 additions & 8 deletions tests/integration/test_readme.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
# limitations under the License.


import pytest

from neo4j.exceptions import ServiceUnavailable
from pathlib import Path


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

# === START: README ===
from neo4j import GraphDatabase

driver = GraphDatabase.driver("neo4j://localhost:7687",
auth=("neo4j", "password"))
# === END: README ===
driver = GraphDatabase.driver(uri, auth=auth)
# === START: README ===

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

def print_friends(tx, name):
for record in tx.run(
"MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
"RETURN friend.name ORDER BY friend.name", name=name):
query = ("MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
"RETURN friend.name ORDER BY friend.name")
for record in tx.run(query, name=name):
print(record["friend.name"])

with driver.session() as session:
# === END: README ===
session.run("MATCH (a) DETACH DELETE a")

# === START: README ===
session.execute_write(add_friend, "Arthur", "Guinevere")
session.execute_write(add_friend, "Arthur", "Lancelot")
session.execute_write(add_friend, "Arthur", "Merlin")
session.execute_read(print_friends, "Arthur")

# === END: README ===
session.run("MATCH (a) DETACH DELETE a")
# === START: README ===

driver.close()
# === END: README ===
assert names == {"Guinevere", "Lancelot", "Merlin"}


def test_readme_contains_example():
test_path = Path(__file__)
readme_path = test_path.parents[2] / "README.rst"

with test_path.open("r") as fd:
test_content = fd.read()
with readme_path.open("r") as fd:
readme_content = fd.read()

stripped_test_content = ""

adding = False
for line in test_content.splitlines(keepends=True):
if line.strip() == "# === START: README ===":
adding = True
continue
elif line.strip() == "# === END: README ===":
adding = False
continue
if adding:
stripped_test_content += line

assert stripped_test_content in readme_content
32 changes: 28 additions & 4 deletions tests/unit/async_/work/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@
from ...._async_compat import mark_async_test


@contextmanager
def assert_warns_tx_func_deprecation(tx_func_name):
if tx_func_name.endswith("_transaction"):
with pytest.warns(DeprecationWarning,
match=f"{tx_func_name}.*execute_"):
yield
else:
yield


@mark_async_test
async def test_session_context_calls_close(mocker):
s = AsyncSession(None, SessionConfig())
Expand Down Expand Up @@ -237,17 +247,25 @@ async def test_session_run_wrong_types(fake_pool, query, error_type):
await session.run(query)


@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction"))
@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction",
"execute_write", "execute_read",))
@mark_async_test
async def test_tx_function_argument_type(fake_pool, tx_type):
called = False

async def work(tx):
nonlocal called
called = True
assert isinstance(tx, AsyncManagedTransaction)

async with AsyncSession(fake_pool, SessionConfig()) as session:
await getattr(session, tx_type)(work)
with assert_warns_tx_func_deprecation(tx_type):
await getattr(session, tx_type)(work)
assert called


@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction"))
@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction",
"execute_write", "execute_read"))
@pytest.mark.parametrize("decorator_kwargs", (
{},
{"timeout": 5},
Expand All @@ -259,12 +277,18 @@ async def work(tx):
async def test_decorated_tx_function_argument_type(
fake_pool, tx_type, decorator_kwargs
):
called = False

@unit_of_work(**decorator_kwargs)
async def work(tx):
nonlocal called
called = True
assert isinstance(tx, AsyncManagedTransaction)

async with AsyncSession(fake_pool, SessionConfig()) as session:
await getattr(session, tx_type)(work)
with assert_warns_tx_func_deprecation(tx_type):
await getattr(session, tx_type)(work)
assert called


@mark_async_test
Expand Down
32 changes: 28 additions & 4 deletions tests/unit/sync/work/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@
from ...._async_compat import mark_sync_test


@contextmanager
def assert_warns_tx_func_deprecation(tx_func_name):
if tx_func_name.endswith("_transaction"):
with pytest.warns(DeprecationWarning,
match=f"{tx_func_name}.*execute_"):
yield
else:
yield


@mark_sync_test
def test_session_context_calls_close(mocker):
s = Session(None, SessionConfig())
Expand Down Expand Up @@ -237,17 +247,25 @@ def test_session_run_wrong_types(fake_pool, query, error_type):
session.run(query)


@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction"))
@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction",
"execute_write", "execute_read",))
@mark_sync_test
def test_tx_function_argument_type(fake_pool, tx_type):
called = False

def work(tx):
nonlocal called
called = True
assert isinstance(tx, ManagedTransaction)

with Session(fake_pool, SessionConfig()) as session:
getattr(session, tx_type)(work)
with assert_warns_tx_func_deprecation(tx_type):
getattr(session, tx_type)(work)
assert called


@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction"))
@pytest.mark.parametrize("tx_type", ("write_transaction", "read_transaction",
"execute_write", "execute_read"))
@pytest.mark.parametrize("decorator_kwargs", (
{},
{"timeout": 5},
Expand All @@ -259,12 +277,18 @@ def work(tx):
def test_decorated_tx_function_argument_type(
fake_pool, tx_type, decorator_kwargs
):
called = False

@unit_of_work(**decorator_kwargs)
def work(tx):
nonlocal called
called = True
assert isinstance(tx, ManagedTransaction)

with Session(fake_pool, SessionConfig()) as session:
getattr(session, tx_type)(work)
with assert_warns_tx_func_deprecation(tx_type):
getattr(session, tx_type)(work)
assert called


@mark_sync_test
Expand Down