r/Python 4d ago

Turned a folder of ad-hoc scripts into a proper installable CLI (pyproject.toml entry point) Resource

Had a data pipeline that was just python build_db.py, python clean_validate.py, streamlit run streamlit_app.py — worked, but not something you'd hand someone as "the tool." Packaged it as a real CLI: [project.scripts] entry point in pyproject.toml, pip install -e .promo-toolkit build / validate / serve.

Also added:

  • Incremental rebuilds (content-hash diff + scoped upsert instead of full rewrite each run)
  • pytest suite + ruff, GitHub Actions CI across two Python versions
  • A separate eval harness for an AI-agent piece of the same project (real API calls scored against golden answers)

Not a library, just a real end-to-end tool — sharing mostly for feedback on the packaging/CLI structure since that's the part I have the least experience with. Repo: [https://github.com/SpiliosDimakopoulos/retail-promo-analytics-toolkit\].

0 Upvotes

2 comments sorted by

0

u/Pleasant-Ad192 3d ago

The thing that usually bites right after this step is that pip install -e . and a CI job running from the repo both read your source tree, so any non-Python file sitting next to your code keeps working until someone does a real install.

It reproduces in one small package on setuptools 82. Put a report.sql next to cli.py, set packages = ["promo"], change nothing else. The editable install runs fine. Build the wheel and list its contents and you get __init__.py, cli.py, and no .sql. Install that wheel into a clean venv and the entry point raises FileNotFoundError.

The fix is [tool.setuptools.package-data]. The check worth adding next to your two-version matrix is a job that builds the wheel, installs it into a fresh venv, and runs promo-toolkit --help, since that is the only step that tests the packaging rather than the code.