Skip to content

Modernize packaging + CI: setup.cfg -> pyproject.toml, legacy workflow -> wads uv stub - #2

Merged
thorwhalen merged 5 commits into
masterfrom
claude/rollout-modernize
Aug 4, 2026
Merged

Modernize packaging + CI: setup.cfg -> pyproject.toml, legacy workflow -> wads uv stub#2
thorwhalen merged 5 commits into
masterfrom
claude/rollout-modernize

Conversation

@thorwhalen

Copy link
Copy Markdown
Member

Summary

Brings videostream2py from the legacy generation (setup.cfg + setup.py +
a hand-rolled ~90-line workflow) onto the current wads standard: a
pyproject.toml single source of truth with a hatchling backend, and a 5-line
ci.yml stub that calls the reusable workflow i2mint/wads/.github/workflows/uv-ci.yml@master.

Merging this PR publishes a release to PyPI. Pushing to master runs the
publish job, which bumps 0.0.2 to the next patch, uploads to PyPI, and pushes
the version bump back. That is intended — but it is a release, not just a config
change.

What changed

Five commits, one concern each:

  1. setup.cfg/setup.py -> pyproject.toml (hatchling) + .editorconfig
  2. fix: declare the missing opencv-python runtime dependency (see below)
  3. CI: legacy workflow -> wads uv reusable-workflow stub
  4. docs: add the two missing top-level module docstrings
  5. style: ruff format (quote normalization; axblack -> ruff)

Inventory carried across from setup.cfg

setup.cfg pyproject.toml
name = videostream2py [project].name
version = 0.0.2 [project].version — deliberately kept at the released PyPI version so CI's auto-bump on merge yields the next patch
description [project].description
long_description = file:README.md + text/markdown [project].readme = "README.md"
url [project.urls].Homepage
license = apache-2.0 license = "Apache-2.0" (SPDX string form; LICENSE kept and now shipped in the wheel's dist-info/licenses/)
install_requires = stream2py [project].dependencies
packages = find: hatchling auto-discovery (verified: the built wheel contains both modules)
platforms = any Operating System :: OS Independent classifier

Nothing was dropped: there were no entry_points/console_scripts, no
package_data, no extras, and no MANIFEST.in/requirements.txt.
include_package_data, zip_safe, description_file, root_url and
display_name are setuptools-/wads-legacy-only keys with no pyproject equivalent.

Filled in what setup.cfg left empty: authors, keywords, classifiers,
requires-python = ">=3.10".

docsrc/conf.py is untouched and still works — epythet's parse_config falls back
to pyproject.toml when setup.cfg is absent.

Latent bug found and fixed

videostream2py/video.py has a module-level import cv2, but opencv-python was
never declared (and stream2py declares no dependencies of its own). A clean
pip install videostream2py therefore produced a package whose only module could
not be imported:

>>> import videostream2py.video
ModuleNotFoundError: No module named 'cv2'

Latent since 0.0.2. Fixed by declaring opencv-python, plus a [tool.wads.ops.libgl]
entry so CI installs libGL on Linux if the runner image ever lacks it (the
opencv-python wheels link against it). On today's runner the check reports
libgl is already installed, so it is a no-op safety net.

testpaths

wads-migrate emits testpaths = ["tests"] unconditionally, and wads CI runs
pytest --doctest-modules with no path argument — so on a repo with no
top-level tests/ dir that setting collects nothing while still reporting green.
Pointed it at the package dir instead. Verified in the branch CI log: the package
is now collected and videostream2py/video.py shows up in the coverage report
(i.e. it is really imported), which is what makes the cv2 gap detectable at all.

Gate results

priv test-dependents videostream2py
baseline (master) no-tests — 0 pass, 0 fail, 1 no-tests
final (this branch) pass — 1 pass, 0 fail, 0 no-tests

Also verified locally: ruff check clean, ruff format --check clean,
uv build produces a correct sdist + wheel.

Branch CI

https://github.com/i2mint/videostream2py/actions/runs/30859318643success

Read Configuration    success
Validation (3.10)     success
Validation (3.12)     success
Windows Tests         success
Publish               skipped   (default-branch gated)
Publish GitHub Pages  skipped   (default-branch gated)

Previous master run was red, so this also clears the repo's red-CI finding.

Note: the test matrix widens from 3.10-only to 3.10 + 3.12 + Windows, and
docstring validation moves from pylint C0114 to ruff D100.

Secrets

The old workflow referenced PYPI_USERNAME and PYPI_PASSWORD. The uv CI uses
token-only PyPI auth, so the stub passes only PYPI_PASSWORD; PYPI_USERNAME is
obsolete. No other secrets were referenced, so [tool.wads.ci.env] stays empty.

Deliberately left undone

  • No tests. The repo still has zero test files and zero executable doctests
    (the one docstring example needs a camera and is +SKIPed). Out of scope for a
    packaging pass; belongs to a test-coverage pass.
  • Package exports nothingfrom videostream2py import VideoCapture still
    fails. That is an API change, not a packaging change, so it is filed separately
    as Package exports nothing: from videostream2py import VideoCapture fails #1.

Also done (repo settings, not in this diff)

Homepage set to the docs URL, topics synced from the new keywords, Discussions
enabled — the ecosystem defaults.

Converts the legacy setuptools packaging to the modern wads layout.

Carried across from setup.cfg verbatim:
  name=videostream2py, version=0.0.2 (matches the released PyPI version, so
  CI's automatic bump on merge produces the next patch), description,
  long_description (README.md, text/markdown -> readme), url -> project.urls
  Homepage, license apache-2.0 -> SPDX "Apache-2.0" string form,
  install_requires (stream2py), packages=find: -> hatchling auto-discovery.
  There were no entry_points/console_scripts, no package_data, no extras and
  no MANIFEST.in/requirements.txt, so nothing else to carry.
  include_package_data/zip_safe/platforms are setuptools-only and drop out;
  "any" platform is now expressed as an OS Independent classifier.

Filled in what setup.cfg left empty: authors, keywords, classifiers,
requires-python (>=3.10).

Also adds the standard [tool.ruff] block (without it the repo falls through
to ruff's moving default and goes red on unrelated style drift) and the
missing .editorconfig.

testpaths is set to the package dir rather than the generated ["tests"]:
wads CI runs pytest --doctest-modules with no path argument, so collection is
driven entirely by testpaths, and ["tests"] (a dir this repo does not have)
would silently collect nothing while still reporting green.

docsrc/conf.py keeps working unchanged: epythet's parse_config falls back to
pyproject.toml when setup.cfg is absent.

Claude-Session: https://claude.ai/code/session_01VipiLaG4xy7WctqY9w2475
videostream2py/video.py has a module-level `import cv2`, but setup.cfg only
ever declared `stream2py` (which itself declares no dependencies). So a clean
`pip install videostream2py` produced a package whose only module could not be
imported:

    >>> import videostream2py.video
    ModuleNotFoundError: No module named 'cv2'

This has been latent since 0.0.2 and went unnoticed because the legacy CI ran
pytest in an environment where `isee install-requires` plus the runner image
happened to satisfy it, and because nothing imported the module in a clean env.

Adds `opencv-python` to [project].dependencies, and a [tool.wads.ops.libgl]
entry so CI installs libGL on Linux when the runner image lacks it (the
opencv-python wheels link against it; the check is a no-op when it is already
present).

Claude-Session: https://claude.ai/code/session_01VipiLaG4xy7WctqY9w2475
Replaces the ~90-line legacy workflow (setup-python@v2, checkout@v2, axblack,
pylint, twine, isee) with the 5-line stub that calls
i2mint/wads/.github/workflows/uv-ci.yml@master. All configuration now lives in
pyproject.toml under [tool.wads.ci.*], so this repo picks up wads CI fixes
without an edit here.

Secret transport: the old workflow referenced PYPI_USERNAME and PYPI_PASSWORD.
The uv CI uses token-only PyPI auth, so only PYPI_PASSWORD is passed through;
PYPI_USERNAME is no longer needed. No other secrets were referenced, so nothing
else had to be carried into [tool.wads.ci.env].

Behavioural deltas worth knowing:
  - tests now run on the 3.10 + 3.12 matrix (was 3.10 only) plus Windows
  - docstring validation moves from pylint C0114 to ruff D100
  - publishing stays gated on the default branch and on validation passing

Claude-Session: https://claude.ai/code/session_01VipiLaG4xy7WctqY9w2475
Both modules lacked one. The legacy CI enforced this via pylint C0114 (and was
failing on it); the new CI enforces the same thing via ruff D100, which is
selected in [tool.ruff.lint]. Docstrings are also what epythet extracts to
build the published API docs, so the package page was empty.

Claude-Session: https://claude.ai/code/session_01VipiLaG4xy7WctqY9w2475
Pure formatting, no behaviour change. The old CI formatted with axblack
(single quotes); the new CI runs `ruff format`, which normalizes to double
quotes. Doing it here keeps the first post-merge CI push-back commit empty of
unrelated churn.

Claude-Session: https://claude.ai/code/session_01VipiLaG4xy7WctqY9w2475
@thorwhalen
thorwhalen merged commit bf3fc33 into master Aug 4, 2026
12 checks passed
@thorwhalen
thorwhalen deleted the claude/rollout-modernize branch August 4, 2026 13:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant