PEP 621 dynamic and optional-dependencies

Reading the PEP to me it’s not clear how dynamic applies for optional-dependencies. Namely, how this fields works with nested values:

[project]
dynamic=["optional-dependencies"]

Does this translate all optional dependencies are dynamic?

[project]
dynamic=["optional-dependencies.docs"]

Do we use dot to separate nested keys? Or that’s not valid and you can only exclude the entire section?

Yes it does.

Haven’t stated anywhere explained this in the PEP, what about marking sub-parts optional? Do we support that?

No it’s all or nothing

Is this somewhere codified or it’s what you’d prefer to happen?

It’s right in your link :slightly_smiling_face:

Build back-ends MUST raise an error if the metadata specifies a field statically as well as being listed in dynamic.

That just could mean that you can’t have:

[project]
optional-dependencies.docs = [
   "A",
]
dynamic=["optional-dependencies.docs"]

Not that this would be invalid:

[project]
optional-dependencies.test = [
   "A",
]
dynamic=["optional-dependencies.docs"]

Also that sentence doesn’t cover how dynamic behave for nested information at all. Just means that you can’t specify the same key dynamically and statically. It does not address if only top level elements can be marked dynamic or the dynamic keyword applies at nested level too.

My understanding at the time was that it would be all or nothing. A PEP to alter this would be acceptable, or a clarification PR to make it explicit. The difference is because I think there’s more complexity in allowing nested parts than in simply making a blanket “top level only” rule explicit.

1 Like

I see most backends implemented assuming you can’t mark individual subkeys dynamic in sections, however the text of the PEP clearly does not make any judgment in either direction so either interpretation I consider equally valid. I think we don’t really need a PEP here however we should add a PR to clarify this edge case. I personally can see a valid use case for allowing sub-key dynamic. Just because your test extras is dynamic that does not mean other extra groups can’t be static; and feels like there’s no real reason to force everything to become dynamic if just one of your extra group needs to be dynamic.

Given that tools have taken the “top level only” view, I don’t think a PR to make that explicit would be controversial, so no PEP should be needed for that. But asking tools to change probably is controversial. So I’d be surprised if you could get consensus for doing that without a PR.

I’ll also note that PEP 643 and the core metadata spec are absolutely “all or nothing” as the Dynamic field must contain field names, and Requires-Dist is a single field. Having the rules for pyproject.toml be subtly different seems like a bad idea to me…

2 Likes

If you take that view @pf_moore would also imply that setting either of the dependencies or optional-dependencies dynamic automatically makes both of them dynamic, because they do map to a single Requires-Dist field and:

Hatchling interprets that as verboten based on the PEP and catches such cases hatch/backend/src/hatchling/metadata/core.py at hatchling-v1.9.0 · pypa/hatch · GitHub

So if I want to declare my optional dependencies in mutliple files, how should I address them?

[project]
dynamic=["optional-dependencies"]

[tool.setuptools.dynamic]
optional-dependencies = [{file = 'dev-requirements.txt'}, {file='test-requirements.txt'}]

Is this acceptable?

If I remember it correctly:

[project]
name = "..."  # Mandatory
version = "..."  # if not `dynamic`
dynamic = ["optional-dependencies"]

[tool.setuptools.dynamic.optional-dependencies]
<name of your extra> = {file = ['dev-requirements.txt', 'test-requirements.txt']}

If it does not work, please have a look on the docs and/or open a discussion/issue in setuptools.

And how can I group multiple optional dependencies together in this way? Imagine having an all alias which installs all groups of optional dependencies.

Referencing other groups is not supported yet. If you would like to work on a PR, I am more than happy to give pointers (but then let’s move it to a setuptools discussion, so we avoid notifying everyone in this thread).

1 Like

I’m pretty sure that you can do one = [“mypackagename[other]”] to refer to the other extras.

2 Likes