Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Python inventory project: validate a batch before replacing stored state

Last updated: 30 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

A staged inventory update computes a candidate state and commits it only after every transition satisfies the stock invariant.

Download Python source kit

Operation contract

The ledger copies its current stock, applies signed changes to that candidate and rejects any negative result. A failed batch leaves the original state intact; a later valid batch commits both item changes. The snapshot method returns another outer dictionary copy so ordinary caller changes do not edit the ledger directly.

Failure and ownership boundary

This model uses scalar integer values and runs in one thread. It provides process-local all-or-nothing mutation, not durable transactions, authorization or concurrent compare-and-set. A sequence that dips below zero and later recovers is still rejected because each transition must be valid. Python sqlite3 transactions: bind values and roll back failed batches is a separate persistence implementation.

Working program

python
class InventoryLedger:
    def __init__(self):
        self._stock = {"paper": 8, "ink": 4}

    def apply(self, changes):
        if len(changes) > 100:
            raise ValueError("batch too large")
        candidate = self._stock.copy()
        for item, change in changes:
            if item not in candidate or type(change) is not int:
                raise ValueError("known item and integer change required")
            next_quantity = candidate[item] + change
            if next_quantity < 0:
                raise ValueError("negative stock")
            candidate[item] = next_quantity
        self._stock = candidate

    def snapshot(self):
        return self._stock.copy()

ledger = InventoryLedger()
try:
    ledger.apply([("paper", -2), ("ink", -9)])
except ValueError:
    print("batch rejected")
print(ledger.snapshot())
ledger.apply([("paper", -2), ("ink", 1)])
print(ledger.snapshot())

Output

Output
batch rejected
{'paper': 8, 'ink': 4}
{'paper': 6, 'ink': 5}

Costs and limits

Copying s stock keys and checking n changes takes expected O(s+n) time and O(s) candidate storage. The fixture starts with two keys; unrestricted state size, concurrency and crash recovery are not addressed.

Common Mistakes

  • Commit the candidate only after every transition passes.
  • A local dictionary is not durable or thread-safe storage.

Connected lessons

Python dictionaries: insertion order and duplicate-key replacement, Python properties: validate mutation at the public attribute boundary, Python sqlite3 transactions: bind values and roll back failed batches, Java multi-map invariants: one lock for a reservation boundary.

Apply this boundary

Python rollback exercise: reject a later failure without keeping earlier edits, Python locks: protect the complete inventory transition.

Related Python operation checks

Python SQLite job project: reject conflicting replays by request identity.

python
inventory-project
Storage details