DEV Community

BotHot
BotHot

Posted on

Check Shopify product handles before import: unique, URL-safe, contiguous (Python)

Shopify rejects or silently merges product rows when the Handle column is wrong. Before importing, I run a small check that needs only the standard library.

What it checks

  • empty handles
  • handles that are not URL-safe (spaces, capitals, underscores)
  • a handle that comes back after other products (variants must be contiguous)
  • two rows with a title for the same handle

The script

import csv, re, sys

SLUG = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")

def check(path):
    problems = []
    seen = {}
    with open(path, newline="", encoding="utf-8-sig") as f:
        reader = csv.DictReader(f)
        last_handle = None
        closed = set()
        for line, row in enumerate(reader, start=2):
            handle = (row.get("Handle") or "").strip()
            title = (row.get("Title") or "").strip()
            if not handle:
                problems.append((line, "empty handle"))
                continue
            if not SLUG.match(handle):
                problems.append((line, f"handle not URL-safe: {handle!r}"))
            if handle != last_handle:
                if handle in closed:
                    problems.append((line, f"handle {handle!r} reappears after other products"))
                if last_handle is not None:
                    closed.add(last_handle)
                last_handle = handle
            if title:
                if handle in seen and seen[handle] != line:
                    problems.append((line, f"second product row with title for handle {handle!r} (first at line {seen[handle]})"))
                else:
                    seen[handle] = line
    return problems

if __name__ == "__main__":
    probs = check(sys.argv[1])
    for line, msg in probs:
        print(f"line {line}: {msg}")
    print(f"{len(probs)} problem(s)")
    sys.exit(1 if probs else 0)
Enter fullscreen mode Exit fullscreen mode

Test run

With a small CSV containing one bad handle, one split product and one empty handle:

line 4: handle not URL-safe: 'Red Mug'
line 5: handle 'blue-mug' reappears after other products
line 5: second product row with title for handle 'blue-mug' (first at line 2)
line 7: empty handle
4 problem(s)
Enter fullscreen mode Exit fullscreen mode

The exit code is 1 when problems are found, so you can use it in a script or CI step.

Notes

  • utf-8-sig handles the BOM that Excel adds.
  • Line numbers match the spreadsheet row, since the header is line 1.
  • It does not check images, prices or SKUs; that is a separate check.

Free small scripts like this live in my repo: https://github.com/skeil1996-ui/python-automation-scripts-free

Top comments (0)