A staged-state exercise verifies that a rejected batch leaves the previously accepted state unchanged.
Python rollback exercise: reject a later failure without keeping earlier edits
Operation contract
The inventory adjustment copies current quantities into a candidate map, applies validated changes there, and returns the replacement only after every change passes. The first edit in the failing fixture would be valid, but a later edit would make stock negative. The caller keeps its original dictionary because the function never mutates it.
Failure and ownership boundary
The operation accepts at most 32 changes, known keys and bounded exact integers. This is local state staging, not a database transaction or protection against another thread replacing stock at the same time. Extend the exercise by checking empty batches, duplicate key edits and a failure at each possible position. Python locks: protect the complete inventory transition requires a wider critical section.
Working program
def adjusted_stock(stock, changes):
if len(changes) > 32 or any(type(value) is not int or not 0 <= value <= 1000 for value in stock.values()):
raise ValueError("stock budget")
candidate = stock.copy()
for label, delta in changes:
if label not in candidate or type(delta) is not int or abs(delta) > 1000:
raise ValueError("invalid adjustment")
quantity = candidate[label] + delta
if not 0 <= quantity <= 1000:
raise ValueError("quantity out of range")
candidate[label] = quantity
return candidate
stock = {"paper": 12, "ink": 4}
try:
adjusted_stock(stock, [("paper", -2), ("ink", -5)])
except ValueError:
print("batch rejected")
print(stock)
print(adjusted_stock(stock, [("paper", -2)]))Output
batch rejected
{'paper': 12, 'ink': 4}
{'paper': 10, 'ink': 4}Costs and limits
Copying s stock entries costs O(s) time and storage, then c changes cost expected O(c) dictionary work. The fixture does not cap the caller’s pre-existing map size; an external service must set that limit too.
Common Mistakes
- Mutating the original map and trying to undo edits is a different failure contract.
- A returned replacement must still be published under an appropriate concurrency policy.
Connected lessons
Python inventory project: validate a batch before replacing stored state, Python locks: protect the complete inventory transition, Python SQLite project: transactional batches, duplicate IDs and reopen checks.
