fix(packaging): include readme-renderer's dependency versions in renderer_version - #20516
Open
IshanA2007 wants to merge 1 commit into
Open
IshanA2007 wants to merge 1 commit into
IshanA2007 wants to merge 1 commit into
Conversation
…erer_version readme-renderer delegates actual rendering to docutils, Pygments, nh3, and a markdown backend (cmarkgfm/comrak). A version bump in any of those can change the rendered HTML for a given description even though readme-renderer's own version hasn't changed, so the periodic update_description_html task never notices and stale descriptions are never re-rendered. renderer_version() now returns a composite "package==version" string covering readme-renderer plus whichever of its rendering dependencies are installed, skipping any that aren't present. The result is cached with functools.cache, since the installed distribution set can't change within a process lifetime and importlib.metadata.distribution() is an uncached sys.path walk. Fixes pypi#19232
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #19232
Problem
update_description_htmlre-renders a description wheneverreadme-renderer's own version doesn't match the storedrendered_by. Butreadme-rendererdelegates the actual rendering todocutils,Pygments,nh3, and a markdown backend (cmarkgfmhistorically,comrakin the version we currently pin). A bump to any of those can change the rendered HTML whilereadme-renderer's own version stays put, so the periodic task never notices and the stale descriptions are never re-rendered.Fix
renderer_version()now returns a compositepackage==versionstring coveringreadme-rendererplus whichever of its rendering dependencies are installed, e.g.:Dependencies that aren't installed are skipped, so listing both markdown backends is safe. The result is cached with
functools.cache: the installed distribution set can't change within a process lifetime, andimportlib.metadata.distribution()is an uncachedsys.pathwalk thatrenderer_version()sits in front of on the upload path.rendered_byis an unconstrainedTextcolumn and its only reader is the admin release-detail page, which prints it verbatim, so the longer, human-readable string is safe and keeps the value debuggable at a glance (which is why I kept it as a readable string rather than hashing the dependency set).Operational note
Every stored
rendered_bytoday is a bare version string, so none of them will match the new composite format andupdate_description_htmlwill re-render every description once. That task is.limit(500)on a*/5crontab, i.e. 144,000 rows/day, so with PyPI's description count this is a multi-week pass rather than a spike. It isn't free, though, and it's worth deciding whether you want the batch limit raised or a one-off backfill instead.This is the same event that already happens on every
readme-rendererbump today, since the filter is a plain!=on the whole value. What changes is the frequency: full invalidation moves from readme-renderer's release cadence to any dependabot bump ofdocutils/Pygments/nh3/comrak. If that's too often for the fleet to converge, happy to adjust.Open question
I hardcoded the dependency list to the packages named in the issue. The alternative is deriving it from
importlib.metadata.requires("readme-renderer")(which returns['nh3>=0.2.14', 'docutils>=0.21.2', 'Pygments>=2.5.1', 'comrak>=0.0.11; extra == "md"']), so a future backend swap would be picked up automatically. I went with the explicit list because it keeps you in control of what can trigger a fleet-wide re-render, and it already covers both markdown backends. Happy to switch if you'd prefer the derived version.Testing
Added unit tests for the composite format, for gracefully skipping a dependency that isn't installed, and for the actual regression: bumping only a dependency's version changes
renderer_version(). Verified the new tests fail against the old implementation.tests/unit/utils/test_readme.pyandtests/unit/packaging/test_tasks.pypass,warehouse/utils/readme.pyis at 100% statement and branch coverage, andruff check,ruff format --check, andmypyare clean.Prepared with AI assistance (Claude).