Requirements.txt as Discipline: Stdlib-Only Scripts Need No Install
The second time I ran my upload batch, I got the email I had been dreading. A channel had flagged my account for double-posting. Nothing had gone wrong with the art. Nothing had crashed. My pipeline had simply done its job twice, and now I was sitting there writing an apology to a stock platform over a batch of files I had already posted. That day I changed three things: I split my pipeline into small standalone scripts, I made two of them depend on nothing but the Python standard library, and I wrote a tracker so a re-run could never double-post again. After that, I packaged 39 finished products, 856 MB of output, with a toolset that runs on a single-core, 2 GB server.
The problem with a fat environment
Every side project starts with a frameworks wish list. Then reality shows up: a two year old script that only works because of a pinned dependency from a version you can't remember, a server with 2 GB of RAM where even installing packages takes forever, and an eventual move to a new machine that breaks everything quietly. When your pipeline codes packaging and metadata, what really hurts is brittleness.
So I built the pipeline as four separate scripts. Two of them, make_metadata.py and upload_tracker.py, use only the standard library. make_metadata.py builds the exact Adobe (5-col), Vecteezy (4-col) and Dreamstime (15-col) upload CSVs from a folder of files. upload_tracker.py is a ledger that remembers what you have already posted, so a re-run never double-posts. No install. No venv. python make_metadata.py ./my-assets --platform adobe --out metadata.csv --ext .jpg and the header the platform demands comes out, nothing else. The other two, md2pdf.py and pack_product.py, do need packages: Pillow for the covers and reportlab for PDF output. That is the entire dependency list. Two packages, and only two, and they are isolated in the two scripts that actually need to render pixels or pages.
That split is the whole point. A CSV generator and a ledger are pure text and logic. They have no business pulling in an image library, and when they do not, you can run them anywhere Python exists. Python 3.9+, a venv, pip install -r requirements.txt. If you only use the two stdlib scripts, you skip the install entirely.
Platform rules are the spec
The thing that makes metadata generation a good fit for a dependency free script is that the platforms publish their rules. All three channels reject a wrong CSV header instantly, which means the header is not a suggestion. make_metadata.py writes the header they demand. Not a superset, not a comment line someone thought was helpful, just the header. When I say the 300+ pages of research behind this pipeline matter, this is what I mean: the rules the scripts enforce are the same rules that got my files rejected before I read them properly.
The tracker follows the same logic. The fastest way to get an account flagged is running your batch twice, so upload_tracker.py pending items.txt shows what is not done yet, upload_tracker.py done "asset-001.jpg" records one, and status tells you where you stand. Nothing clever. A ledger file and some string handling. That is exactly why it has survived every environment change since.
The pattern generalizes
Once I saw how well the split worked, I applied it to the slow parts. On a 1 vCPU, 2 GB box with no GPU, the pipeline only works if you respect those limits:
- One process at a time. Never fan out image jobs in parallel on a single-core box.
- Call
gc.collect()after each asset so memory actually comes back. - Measure peak RSS with
resource.getrusage(RUSAGE_SELF).ru_maxrss, not average. The ceiling is what kills you. - Run heavy render steps one file per subprocess, so memory returns to the OS.
- Inspect previews at 60 dpi instead of rendering at 300.
And keep a fixed folder layout, because a catalogue turns into a junk drawer without one:
project/
assets/ raw output (one file per asset)
output/ ready-to-submit files + metadata.csv
packs/ finished product zips + covers
research/ your notes and sources
scripts/ these tools
Keep research/ forever. Deleting scrape logs to clean up was the mistake this project made once and won't repeat. That folder is the raw material for future products.
What the kit is for
The four scripts are the packaging layer of a prompt engine that turned one input into 39 finished products. The parent project is roughly 19,000 lines of pipeline code. The packaging tools themselves are the part you can pick up today: build the CSVs, track what you have posted, turn a Markdown doc into a product PDF, zip it with a 1280x720 cover and a 600x600 thumbnail. make_metadata.py and upload_tracker.py run on the standard library alone. pack_product.py writes into a _system folder and takes --dir or PACK_ROOT if you want it elsewhere. No framework, no cloud account.
I did not write this as a tutorial that ends at here is how you would do it. I wrote it because running your batch twice and getting flagged is a pain I would rather you avoid. The scripts did that for me.
Building digital products? Free guides & kits for digital product sellers.
Top comments (0)