PEP 621: round 3

Did you see this?

Without specifying between “backend-supplied” and “give me the default value”, there’s an ambiguity for anyone reading the data as to whether you want the default value or whether it’s being pulled in from a tool. The use cases where you need dynamic metadata (as opposed to having pyproject.toml as the source of truth for other tools) is much more rare than the use case where you want to accept the default value for a field.

This has a bearing on how even a single backend can be written, since the backend also needs to know if you meant to ask it for a value or if you wanted the default value.

It also has a bearing on people reading these things. In the current PEP 621, if you scan through a pyproject.toml and don’t see something listed as dynamic, you know it just takes the default value. You don’t need to know what backend is being used or what its specific behavior is.

Plus, I think we all pretty much agree that dynamic fields are pretty against the spirit of PEP 621 (which is trying to create a clean, declarative metadata spec), so it’s not really something we want to encourage by making it easy.

I did.

Maybe I have a skewed perception of the ergonomic impact of dynamic because in my practice I often use back-ends that generate metadata from another source (setuptools_scm, setuptools-odoo). Such metadata is actually static in the generated sdist, btw.

I had the impression dynamic was a leftover of the intention of having PEP 621 being the standardized sdist metadata. I now see it is not the case and that is fine.

It could be valuable to say a bit more about the “why” of dynamic in the PEP, as that was not obvious, to me at least.

Thanks for the explanations and all the work on this.

1 Like

On a different topic, I’m a little bit torn by Build back-ends MAY automatically fill in extra trove classifiers if the back-end can deduce the classifiers from the provided metadata which contradicts a little Data specified using this PEP is considered canonical.

I agree that the following sentenceTools CANNOT remove or change data, but they MAY add to it implicitly allows it but it might be worth it to explicitly mention trove classifiers as an other example ?

Edited: in fact, would it make sense to explicitly list the fields that might be “extended” by the backends ?
For example, I feel that the dependencies/optional-dependencies fields should not allow such extensions…

I’d consider this sort of “extending” of fields to be changing data, not adding it. So I’d certainly take the view that dependencies don’t allow this. I don’t read “add to” as meaning “add values to an existing list for a field”. I read “add to” as meaning “provide values for fields not already specified”.

I would actually like to see some justification for classifiers being an exception to the “Tools CANNOT remove or change data” rule.

Given that the PEP says “Build back-ends MUST raise an error if the metadata specifies a field statically as well as being listed in dynamic”, and given that backends are explicitly not allowed to touch fields that are not marked as “dynamic”, how is it even possible for a backend to be in a position to have a “classifiers” value that they are able to add values to in the first place???


Can I ask why you would find it useful? I’m not apposed to adding an example, but it is work on my part and I would rather not do it for completeness but because there’s a specific usefulness to it. Otherwise the translations are pretty straightforward and defined as necessary in the PEP already when they are odd (like with authors).

That’s a core metadata concern, not one for PEP 621 to worry about. Or put another way, unless the core metadata has a restriction, then PEP 621 won’t have a restriction.

Yes. As you noticed, things went back and forth on that topic. :wink:


It’s definitely one of my use cases. :wink:

Sure, I can try to clarify it.

Do note that the example that explains the rule specifies that it allows for making a value more specific, e.g. adding a local version to the overall version since you can’t know that until you build the wheel but you can know the general version statically beforehand.

This is one of the reasons why I think @takluyver argued to just drop all Trove classifier stuff from the PEP. I’m fine taking out the exception for classifiers as that was a bit of a speculation that build back-ends would want to fill in the license and/or supported Python version, but that’s a guess instead of a guarantee. And with Requires-Python and the eventual SPDX support these cases won’t be as useful.

I’ve chosen to output the first one that is defined since those fields aren’t listed as multiple use. Is that correct/logical?

1 Like

I’d say that’s good enough. If any user finds it unsatisfactory, they should lobby a Core Metadata update to clarify those fields.

1 Like

Does that mean that a pyproject.toml containing

version = "1.2.3"

could end up producing sdist & wheels with different versions (1.2.3+something) ?

I’d personally find it strange and would (again) not find this “canonical”.

Agreed, that seems wrong to me. If the user wants the build tool to be allowed to add a local part to the version, they should be saying version is dynamic.

Note: This does somewhat go back to the question of whether it’s OK to have

version = "1.2.3"
dynamic = ["version"]

and what that would mean in practice.

But I’m 100% of the opinion that if a project specifies just

version = "1.2.3"

in pyproject.toml, then it would be an error for any artifact built from that source to have a version other than 1.2.3.


I understood the question to be: is there a definition mapping authors = [TOML list] into repeated Author: xyz entries in the RFC2822-style used for Metadata (question as old as distutils2, and also applies to Classifier[s]).

1 Like

Core Metadata currently defines Author as single-use, so having multiple repeating Author fields is invalid in the current Core Metadata version. A separate Core Metadata version update will be needed to do this, but that should not be a part of the PEP 621 discussion.

1 Like

Thanks for the reminder, I mixed up Author and Classifier!

The PEP explains how to transform authors tables to Author or Author-Email, but does not say explicitly that multiple entries should be joined by a comma to go into the Author metadata value.

1 Like

I thought the point of local versions was for the builder to add it, not the author (the author can just modify their own code). So those who need to do this will just ignore the standard and do their own thing anyway.

This is why I’d prefer to not encourage build tools to aggressively impose these restrictions. We can warn that it may confuse other tools if you do this, but there’s no reason to prevent someone from doing it. If they need it, they need it.

Honestly I’d be happy without the static/dynamic marking and just say “if it’s in there, tools will trust it, if it’s not trustworthy don’t specify it, and specify known empty values as …”. Then if someone makes a package that doesn’t resolve properly because they went against the advice, we blame them (yes, I get that pip is trying to avoid getting the blame for bad PyPI packages, but there’s a whole lot more packaging that goes on besides PyPI with different needs).

I’m not aware of any build backend that does this at the moment - in setuptools, you need to modify to add a local version.

It might well be a good feature to have, but it would be a change, and I don’t think PEP 621 should be in the business of driving a change like this. Conversely, of course, this does imply that PEP 621 is encapsulating current practices. That’s inevitable in a standard that defines a UI for providing information to a tool, though, and if you feel it stifles innovation in build tool UIs, then you’re probably going to have other issues with PEP 621 as well. (That’s one of the reasons Poetry was against PEP 621, as I understand it - it didn’t give them the flexibility to innovate the way they want to).

1 Like

I am in favor of forbidding the specification of a field if that field is marked as dynamic (possibly with the caveat that any non-backend tools should defer to the backend to determine whether or not to throw an error when they encounter this).

We can give it some time, and if people want a “base version” + dynamic, they can put the base version in [tool.setuptools_scm] or something similar and specify the field as dynamic. If the ecosystem starts to converge on this being a useful pattern, we can have a more targeted PEP to allow for the use of dynamic together with version (or other fields).

I will also note that the fact that version must be a string literal will cause some problems for people migrating from setup.cfg (and will necessitate the use of dynamic). In setup.cfg, we allow file: and attr:, which we consider to be static attributes, and which are very popular (in my projects I’ve used all four common ways to specify versions — string literal, pulled from a file, pulled from an attribute and pulled from git metadata). We would need to make those dynamic and put the version metadata in tools.setuptools, which is not ideal.

Of course, I’m not sure if those modes of specifying version number are important for anyone other than setuptools, and it is again something that can be solved in a later PEP in a hopefully backwards-compatible manner by allowing a subtable with a single key in place of a str, so that people can do version: {"file": "VERSION"} or whatever.

I can clarify that.

People seem to be gravitating towards being stricter, so I’ll update the PEP to say this.


Changes to address the latest comments committed in

Anything left to do here, @pf_moore?

No, I think it’s good to go.

… for what? :wink: Are you still PEP delegate or are we naming someone else? And if it’s still you, is “good to go” the same as “accepted” (in which case I will get a PR for ready)?