The HTML representation of the index API is now frozen - The Python Package Index Blog
Skip to content
Initializing search
GitHub
Authors
The HTML representation of the index API is now frozen
PyPI has adopted PEP 833, which "freezes" the<br>HTML representation of the index API, which is also<br>sometimes called the "simple API" or the "simple repository API."
New packages and releases will continue to appear in the HTML<br>representation, meaning this has no breaking implications<br>for downstream index consumers.
However, future standardization and development efforts will focus<br>on the JSON representation, and downstreams that consume only the HTML<br>representation are strongly encouraged to transition to the JSON<br>representation to ensure access to the latest and greatest index features.
Background
As the name suggests, PyPI's primary responsibility is serving a<br>package index. Installers (like pip and uv) consume this<br>index as part of resolving and installing dependencies.
For historical reasons, there are two different standard representations<br>of a Python packaging index:
The HTML representation, which predates standardization, and was<br>retroactively standardized with PEP 503.
The HTML index is essentially a bare-bones version of the<br>human-readable index that PyPI once served, back before PyPI<br>was a resource that installers automatically retrieved packages<br>from. It's that old!
The JSON representation, which was standardized with PEP 691.
Unlike the HTML representation, the JSON representation was designed<br>from the ground-up to be useful to machine clients, rather than<br>humans.
The two representations are more or less1 coextensive in terms of<br>serving the information that installers care about. This is intentional:<br>efforts to extend the simple index over the years have worked hard<br>to put that state into both representations.
Doing so with the HTML representation is often unwieldy, as<br>metadata that naturally fits JSON's object model needs to be<br>shoehorned into nooks and crannies (mainly HTML attributes and new tags)<br>that won't interfere with pre-existing assumptions about the<br>HTML's shape.
Unfortunately, that shoehorning process is has become harder over time:
Many consumers have made suboptimal, unsound assumptions about<br>the shape of shape of PyPI's HTML representation. More<br>precisely: they go beyond assuming the basic shape of the HTML,<br>and actually make assumptions about semantically irrelevant<br>aspects like whitespace, attribute order, &c.
This makes even "shape preserving" changes to the HTML representation<br>fraught.
By contrast, consumers of the JSON representation don't generally<br>encounter these issues. Some of that is probably a function of<br>the JSON representation being newer, but a large part is<br>likely because, unlike HTML, users don't find themselves open-coding<br>a JSON parser in high-level languages.
Because the fundamental shape of the HTML representation can't be changed,<br>adding new pieces of metadata to it becomes an exercise in creative<br>munging: things that are natural to express as object members in<br>JSON need to be shoehorned into new, flat tags or HTML<br>attributes in the HTML representation.
PEP 792 is a good example of this. Compare the JSON representation:
"meta": {<br>"api-version": "1.4"<br>},<br>"project-status": {<br>"status": "quarantined",<br>"reason": "the project is haunted"
...to the HTML one:
meta name="pypi:repository-version" content="1.4"><br>meta name="pypi:project-status" content="quarantined"><br>meta name="pypi:project-status-reason" content="the project is haunted">
This may not seem so bad in isolation, but keep in mind that this<br>flattening and munging needs to happen for every single<br>new addition to the index.
Even when we do successfully shoehorn features into the<br>HTML representation (on paper, and on PyPI), it often<br>doesn't matter to users : users are bifurcated between adoption<br>of the JSON representation (which doesn't have these issues)<br>and third-party (often private) indices that only<br>implement the absolute bare minimum required in PEP 503.
As a result, even when we do update the HTML representation,<br>users rarely benefit from it.
"Freezing" the HTML representation is our way of acknowledging this<br>situation. It's our way of saying that we can't2 deprecate the<br>HTML representation, but that we don't want to keep extending it<br>given how lopsided the tradeoffs are.
Do I have to do anything?
No!
The HTML representation is not going away , and will not<br>go "stale" in terms of content updates. "Freezing" means that<br>Python packaging as a whole has made a policy decision<br>to not continue to munge features into its structure.
In other words: the HTML representation will continue to be served by PyPI<br>for the foreseeable future, but Python packaging as a whole<br>will no longer prioritize attempting to shoe-horn new pieces<br>of metadata into its relatively inflexible HTML structure.
The longer answers:
If you're an "individual" downstream package consumer (e.g., a<br>user who installs...