Skip to content

Commit 92a1a33

Browse files
chore(docs): update docstrings for batches without context managers (#578)
1 parent 85c0232 commit 92a1a33

File tree

4 files changed

+60
-13
lines changed

4 files changed

+60
-13
lines changed

google/cloud/datastore/batch.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,9 @@ def begin(self):
281281
282282
This method is called automatically when entering a with
283283
statement, however it can be called explicitly if you don't want
284-
to use a context manager.
284+
to use a context manager. If used outside a context manager,
285+
`client.get` calls targeting the batch and commit/rollback calls
286+
will need to be managed explicitly as well
285287
286288
Overridden by :class:`google.cloud.datastore.transaction.Transaction`.
287289
@@ -365,6 +367,10 @@ def rollback(self):
365367
366368
Marks the batch as aborted (can't be used again).
367369
370+
This is called automatically upon exiting a with statement,
371+
however it can be called explicitly if you don't want to use a
372+
context manager.
373+
368374
Overridden by :class:`google.cloud.datastore.transaction.Transaction`.
369375
370376
:raises: :class:`~exceptions.ValueError` if the batch is not

google/cloud/datastore/client.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ def _pop_batch(self):
407407

408408
@property
409409
def current_batch(self):
410-
"""Currently-active batch.
410+
"""Currently-active batch, if within the scope of a Batch context manager.
411411
412412
:rtype: :class:`google.cloud.datastore.batch.Batch`, or an object
413413
implementing its API, or ``NoneType`` (if no batch is active).
@@ -417,7 +417,8 @@ def current_batch(self):
417417

418418
@property
419419
def current_transaction(self):
420-
"""Currently-active transaction.
420+
"""Currently-active transaction, if within the scope of a Transaction
421+
context manager.
421422
422423
:rtype: :class:`google.cloud.datastore.transaction.Transaction`, or an
423424
object implementing its API, or ``NoneType`` (if no transaction

google/cloud/datastore/transaction.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,9 @@ def begin(self, retry=None, timeout=None):
212212
213213
This method is called automatically when entering a with
214214
statement, however it can be called explicitly if you don't want
215-
to use a context manager.
215+
to use a context manager. If used outside a context manager,
216+
`client.get` calls targeting the transaction and commit/rollback calls
217+
will need to be managed explicitly as well.
216218
217219
:type retry: :class:`google.api_core.retry.Retry`
218220
:param retry:

tests/system/test_transaction.py

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -148,15 +148,53 @@ def test_failure_with_contention(datastore_client, entities_to_delete, database_
148148

149149
entities_to_delete.append(orig_entity)
150150

151-
with pytest.raises(Conflict):
152-
with local_client.transaction() as txn:
153-
entity_in_txn = local_client.get(key)
151+
with local_client.transaction() as txn:
152+
entity_in_txn = local_client.get(key)
154153

155-
# Update the original entity outside the transaction.
156-
orig_entity[contention_prop_name] = "outside"
154+
# Update the original entity outside the transaction.
155+
orig_entity[contention_prop_name] = "outside"
156+
with pytest.raises(Conflict):
157157
datastore_client.put(orig_entity)
158158

159-
# Try to update the entity which we already updated outside the
160-
# transaction.
161-
entity_in_txn[contention_prop_name] = "inside"
162-
txn.put(entity_in_txn)
159+
# Try to update the entity which we already updated outside the
160+
# transaction.
161+
entity_in_txn[contention_prop_name] = "inside"
162+
txn.put(entity_in_txn)
163+
# now that transaction is complete, should be able to update outside
164+
datastore_client.put(orig_entity)
165+
166+
167+
@pytest.mark.parametrize("database_id", [None, _helpers.TEST_DATABASE], indirect=True)
168+
def test_failure_with_contention_no_context_manager(
169+
datastore_client, entities_to_delete, database_id
170+
):
171+
contention_prop_name = "baz"
172+
local_client = _helpers.clone_client(datastore_client)
173+
174+
# Insert an entity which will be retrieved in a transaction
175+
# and updated outside it with a contentious value.
176+
key = local_client.key("BreakTxnCM3", 1234)
177+
orig_entity = datastore.Entity(key=key)
178+
orig_entity["foo"] = "bar"
179+
local_client.put(orig_entity)
180+
181+
entities_to_delete.append(orig_entity)
182+
183+
txn = local_client.transaction()
184+
txn.begin()
185+
186+
entity_in_txn = local_client.get(key, transaction=txn)
187+
188+
# Update the original entity outside the transaction.
189+
# should fail due to contention
190+
orig_entity[contention_prop_name] = "outside"
191+
with pytest.raises(Conflict):
192+
datastore_client.put(orig_entity)
193+
194+
# Try to update the entity inside the transaction
195+
entity_in_txn[contention_prop_name] = "inside"
196+
txn.put(entity_in_txn)
197+
txn.commit()
198+
199+
# now that transaction is complete, should be able to update outside
200+
datastore_client.put(orig_entity)

0 commit comments

Comments
 (0)