Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: What’s the difference between optional-dependencies and dependency-groups in pyproject.toml? #9011

Closed
pplmx opened this issue Nov 11, 2024 · 10 comments
Labels
question Asking for clarification or support

Comments

@pplmx
Copy link

pplmx commented Nov 11, 2024

Hi,

I have a question regarding the configuration of dependencies in pyproject.toml.

I’ve noticed that both optional-dependencies and dependency-groups seem to handle optional dependencies in a similar way, so I'm a bit confused about how they differ and when each should be used. Could you clarify the following points?

  • Purpose: What is the intended purpose of optional-dependencies versus dependency-groups?

  • Usage Scenarios: In what specific scenarios would it make sense to use one over the other?

Any insights or examples you could provide would be really helpful.

Thanks in advance for your time and assistance!

@PRFina
Copy link

PRFina commented Nov 11, 2024

I was wondering about the same today, looking for some insights here. From my understanding:

  • optional-dependencies (aka package's extras) are meant to be shipped with your code. However, installing them is optional as they provide "extra" features of your package, maybe supporting a smaller set of users. Think about how pandas handle them. Most users want to work with their core API, ie, with Dataframe or Series data structures with some locally stored csv/parquet files. However, some user wants to have extra features to read/write the data from/to some remote storage. To fulfill this purpose they provide pip install pandas[aws,gcp,fss]

  • dependencies-groups are still optional dependencies, but are not meant to be shipped with your package. I'm thinking about all those dependencies that help to support your package development activities (testing, linting, formatting, QA, etc,). Indeed they're called dev dependencies in the doc. For example, I know that the data scientist who works with me like to prototype some code in Jupyter Notebooks first, and then move their code snippets in some py module. Therefore, I'm adding Jupyter as a dependencies-groups dependency since it's not part of the package itself, just the dev workflow.

I think it's more about what ends up in the published package than how they are handled by uv. In theory, you can move all your optional-dependencies into the optional-dependencies table and vice-versa, ending up with the same amount of resolved/installed packages in your venv.

Moreover optional-dependencies are part of the the pep 621 standard specification while dependencies-groups is uv specific. Therefore, the former also works with other pep 621 compliant tools (eg. pip) while the latter only with uv.

I'm new to uv, so they are just considerations. Probably some contributor could shed more light on the rationale behind this feature 😃

@Ravencentric
Copy link

Ravencentric commented Nov 11, 2024

Moreover optional-dependencies are part of the the pep 621 standard specification while dependencies-groups is uv specific. Therefore, the former also works with other pep 621 compliant tools (eg. pip) while the latter only with uv.

They are not uv specific but a fairly new packaging standard defined by PEP 735 – Dependency Groups in pyproject.toml.

project.optional-dependencies are part of your published package and can be installed by the end user via pip install your-package[some-extra] while dependency groups are not published with your package.

@PRFina
Copy link

PRFina commented Nov 11, 2024

Thanks for pointing it out @Ravencentric, I was not aware of it 😄

@pplmx
Copy link
Author

pplmx commented Nov 11, 2024

@PRFina Thanks for your response; it was really helpful!

@charliermarsh charliermarsh added the question Asking for clarification or support label Nov 11, 2024
@charliermarsh
Copy link
Member

See also: #8981 (comment).

@majidaldo
Copy link

Wouldn't this violate DRY? If I'm working on an optional user feature, how do I specify the deps as a dependency-group as well as a project.optional-dependencies without repeating?

@zanieb
Copy link
Member

zanieb commented Jan 2, 2025

If it's a user feature, use project.optional-dependencies instead of dependency-group.

@zanieb
Copy link
Member

zanieb commented Jan 2, 2025

uv does support this though

❯ uv init example
Initialized project `example` at `/Users/zb/workspace/uv/example`

❯ cd example
❯ uv add --optional feat anyio
Using CPython 3.12.8 interpreter at: /opt/homebrew/opt/python@3.12/bin/python3.12
Creating virtual environment at: .venv
Resolved 5 packages in 114ms
Prepared 4 packages in 97ms
Installed 4 packages in 2ms
 + anyio==4.7.0
 + idna==3.10
 + sniffio==1.3.1
 + typing-extensions==4.12.2

❯ uv add --group feat 'example[feat]'
Resolved 5 packages in 2ms
Audited 4 packages in 0.00ms

❯ cat pyproject.toml
[project]
name = "example"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []

[project.optional-dependencies]
feat = [
    "anyio>=4.7.0",
]

[dependency-groups]
feat = [
    "example[feat]",
]

❯ uv sync --group feat
Resolved 5 packages in 1ms
Installed 4 packages in 6ms
 + anyio==4.7.0
 + idna==3.10
 + sniffio==1.3.1
 + typing-extensions==4.12.2

@majidaldo
Copy link

uv does support this though

❯ uv init example
Initialized project `example` at `/Users/zb/workspace/uv/example`

❯ cd example
❯ uv add --optional feat anyio
Using CPython 3.12.8 interpreter at: /opt/homebrew/opt/python@3.12/bin/python3.12
Creating virtual environment at: .venv
Resolved 5 packages in 114ms
Prepared 4 packages in 97ms
Installed 4 packages in 2ms
 + anyio==4.7.0
 + idna==3.10
 + sniffio==1.3.1
 + typing-extensions==4.12.2

❯ uv add --group feat 'example[feat]'
Resolved 5 packages in 2ms
Audited 4 packages in 0.00ms

❯ cat pyproject.toml
[project]
name = "example"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []

[project.optional-dependencies]
feat = [
    "anyio>=4.7.0",
]

[dependency-groups]
feat = [
    "example[feat]",
]

❯ uv sync --group feat
Resolved 5 packages in 1ms
Installed 4 packages in 6ms
 + anyio==4.7.0
 + idna==3.10
 + sniffio==1.3.1
 + typing-extensions==4.12.2

oh ok! b/c i can refer to the package that i'm developing. thanks!

@zanieb
Copy link
Member

zanieb commented Jan 2, 2025

I'm not sure if other tools will accept that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Asking for clarification or support
Projects
None yet
Development

No branches or pull requests

6 participants