unittest the spreadsheet-row to Sume bulk item builder, no network

A pure function that turns a spreadsheet row into a Sume bulk item, with four unittest cases for trimming, price format, a spend cap in range and blank SKUs.

5 min readSume
All posts

Keep the code that turns a spreadsheet row into a Sume bulk item as a pure function, with no network call inside it, and test it with the standard library's unittest. A bulk create validates all items before any queue exists, so a wrong item costs you a whole 400 round trip, and a wrong but valid item costs real money. Both are cheaper to catch in a test that runs in a few milliseconds.

The file below holds the builder and four tests. Run it with python3 items_test.py; it needs no key, no network and no packages.

The builder and its tests

The builder returns one element for the items array. Each element is a normal single-run body, so the fields are those of POST /v1/formats/{handle}/{slug}/runs.

import unittest
def build_item(row, cap=3.0):
    """One spreadsheet row -> one bulk item body."""
    sku = str(row["sku"]).strip()
    if not sku:
        raise ValueError("empty sku")
    return {"instruction": f"15 second product video for {row['title'].strip()}",
            "input": {"sku": sku, "price": f"{float(row['price']):.2f}",
                      "image_url": row["image"].strip()},
            "generation_spend_cap_usd": cap}
class BuildItemTest(unittest.TestCase):
    def test_trims_and_formats(self):
        item = build_item({"sku": " A1 ", "title": " Mug ", "price": "9.5", "image": " https://e.com/a.jpg"})
        self.assertEqual(item["input"], {"sku": "A1", "price": "9.50", "image_url": "https://e.com/a.jpg"})
        self.assertIn("Mug", item["instruction"])

    def test_cap_is_always_set_and_in_range(self):
        item = build_item({"sku": "A1", "title": "t", "price": 1, "image": "u"})
        self.assertTrue(0 < item["generation_spend_cap_usd"] <= 500)

    def test_blank_sku_is_rejected(self):
        with self.assertRaises(ValueError):
            build_item({"sku": "  ", "title": "t", "price": 1, "image": "u"})

    def test_input_stays_flat_and_small(self):
        item = build_item({"sku": "A1", "title": "t", "price": 1, "image": "u"})
        self.assertLessEqual(len(item["input"]), 64)
if __name__ == "__main__":
    unittest.main()

What each test protects

The trim test guards the most common spreadsheet fault: a stray space that turns A1 and A1 into two SKUs in your ledger. The price test fixes the string form once, so the Format always sees 9.50 and never 9.5. Whatever shape you choose for input, you choose it, since the Format reads the keys it knows and ignores the rest.

The cap test asserts that every item has a generation_spend_cap_usd greater than 0 and at most 500. The API rejects 0, rejects anything above 500, and treats a missing cap as the Format's own default. A queue has no total cap of its own, so its worst case is the sum of the item caps, and a per-item cap set in this function is the only budget control a bulk batch has.

The blank-SKU test makes bad rows fail in your code with a row you can find, not later as a failed item with only an index. The last test keeps input flat: at most 64 top-level keys per item, and 2 MiB. If your sheet has more columns, nest them under one key.

Fields the builder sets and the API rule behind each (read 2026-10-07)
FieldSet by the builderAPI rule
instructionProduct title in a fixed sentenceAt least one of instruction, input, previous_run_id, attachments
inputsku, price, image_urlObject, at most 64 top-level keys and 2 MiB
generation_spend_cap_usd3.0 unless overriddenAbove 0 and at most 500

Extending it

Add a case per bug you meet in production: a row with an empty image cell, a price with a thousands separator, a title with a newline. Each becomes a named failing test before it becomes a fix. Run the suite in CI ahead of the step that calls the API, so a broken spreadsheet template never reaches a paid create.

Pair it with a body-level check for item count, concurrency and the 4 MiB limit, which no single-item test can see.

Keep the test data small and fake. Use example.com URLs and invented SKUs; the builder never fetches an image, so nothing in the suite touches a real asset. When a real row broke a production batch, copy only the shape of that row into the test, and leave the real product names and links out of the repository.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume