One pathological case that this (and likely some other implementations of metadata 2.2) gets wrong is the following:
pyproject.toml
:
[project]
dynamic = ["version"]
__init__.py
from random import choice
__version__ = f"{choice(['0.1.0', '0.2.0', '0.3.0'])}"
The problem is that the spec for Metadata 2.3 says:
If a field is not marked as
Dynamic
, then the value of the field in any wheel built from the sdist MUST match the value in the sdist.
That means that the build backend, when provided with sources that include the PKG-INFO
file (i.e., you’re building from a sdist) must prioritise that data, and not re-generate any “dynamic” fields from pyproject.toml
. (Unless, of course, it is certain that doing so cannot cause any discrepancies).
In the above case, if you build a sdist from the project and you get version 0.2.0 (which is recorded in the sdist as static), building a wheel from that sdist must generate version 0.2.0, and not one of the other possibilities. This was a deliberate feature of Metadata 2.2, and is crucial to installers being able to extract sdist metadata without doing a fresh build.
In practice, this is clearly a pathological case designed to break the implementation, so it’s hard to get too worked up about it - but it is technically a spec violation. I don’t recommend marking any field that is dynamic in pyproject.toml
as dynamic in the sdist, though - that would be unnecessary in the vast majority of cases and would defeat the purpose of having metadata 2.2. Instead, I would honestly have expected flit to require that fields calculated at build time like this should be constant literal values from the source, and not allow arbitrary code execution at build time. But if the code execution feature is deliberate, then checking for a PKG-INFO file when code execution could happen is the right approach.
(When I wrote the PEP for Metadata 2.2, I thought setuptools was the only build backend that allowed arbitrary code execution when calculating metadata, and we knew that setuptools had some unique difficulties as a result of this. But I didn’t expect it to be a common issue with other backends, and no-one spoke up at the time pointing out any other cases).