Dependências do seu pacote Python#
Na página de visão geral do pyproject.toml, você aprendeu como configurar um arquivo pyproject.toml com os metadados básicos do seu pacote. Nesta página, você aprenderá como especificar diferentes tipos de dependências no seu pyproject.toml.
O que é uma dependência de pacote?#
A Python package dependency refers to an external package or a tool that is needed
when using or working on your Python project. Declare your dependencies in
your pyproject.toml file. This keeps all package metadata in one place, making
it simpler for users and contributors to understand your package.
Formas antigas de declarar dependências
Embora pyproject.toml agora seja o padrão, às vezes você ainda pode encontrar abordagens mais antigas para armazenar dependências «por aí»:
requirements.txt: Antes era comum para dependências, e ainda é usado por alguns projetos para desenvolvimento local
setup.py ou setup.cfg: Pode ser necessário para pacotes com extensões em outras linguagens
Por que especificar dependências#
Specifying dependencies in the project.dependencies array of your pyproject.toml file ensures that libraries needed to run your package are correctly installed into a user’s environment.
For instance, if your package requires pandas to run properly, and you add pandas to the project.dependencies array, pandas will be installed into the user’s environment when they install your package using uv, pip, or conda.
[project]
...
...
...
dependencies = [
"dependency-package-name-1",
"dependency-package-name-2",
"pandas",
"xarray",
"geopandas",
"matplotlib"
]
Dependências de desenvolvimento facilitam o trabalho dos contribuidores no seu pacote. Você pode configurar instruções para executar workflows específicos, como testes, linting e até tipagem, que instalam automaticamente grupos de dependências de desenvolvimento. Essas dependências podem ser armazenadas em arrays (listas de dependências) dentro de uma tabela [dependency-groups].
[dependency-groups]
test = [
"pytest",
"pytest-cov"
]
Tipos de dependências#
Existem três tipos diferentes de dependências que você aprenderá nesta página:
Dependências obrigatórias: São dependências que precisam ser instaladas para que seu pacote funcione corretamente no ambiente do usuário. Você adiciona essas dependências na tabela
project.dependenciesdo seu arquivo pyproject.toml.Feature Dependencies: These are dependencies that are required if a user wants to access additional functionality (that is not core) to your package. Store these in the
[project.optional-dependencies]of your pyproject.toml file.Development Dependencies: These dependencies are required if someone wants to develop or work on your package. Linters and testing tools such as pytest and mypy are examples of development dependencies. Store these in the
[dependency-groups]table of your pyproject.toml file.
Dica
Uma dependência não faz parte da base de código do seu projeto. Ela é um pacote ou software chamado dentro do código do seu projeto ou usado durante o desenvolvimento do seu pacote.
1. Required dependencies#
Dependências obrigatórias são importadas e chamadas diretamente dentro do código do seu pacote. Elas são necessárias para que seu pacote funcione.
Você pode adicionar suas dependências obrigatórias ao array dependencies na tabela [project] do seu arquivo pyproject.toml. Quando usuários instalarem seu pacote com uv, pip ou conda, essas dependências serão instaladas automaticamente junto com seu pacote no ambiente deles.
[project]
...
...
...
dependencies = [
"dependency-package-name-1",
"dependency-package-name-2",
"pandas",
"xarray",
"geopandas",
"matplotlib"
]
Dica
Tente ao máximo minimizar dependências sempre que possível. Lembre-se de que menos dependências reduzem a possibilidade de conflitos de versão nos ambientes dos usuários.
Como adicionar dependências obrigatórias com UV
Você pode usar uv para adicionar dependências ao seu arquivo pyproject.toml:
Adicionar uma dependência obrigatória:
uv add numpy
Irá adicionar numpy como dependência ao seu array project.dependencies:
[project]
dependencies = [
"numpy>=2.2.6",
]
Dependências instaladas a partir do GitHub/GitLab
Se você tiver dependências que precisam ser instaladas diretamente do GitHub, pode especificá-las no seu arquivo pyproject.toml desta forma:
dependencies = [
"my_dependency >= 1.0.1 @ git+https://git.server.example.com/mydependency.git@commitHashHere"
]
IMPORTANTE: Se sua biblioteca depende de um projeto hospedado no GitHub, você deve apontar para um commit/tag/hash específico desse repositório antes de enviar seu projeto para o PyPI. Você nunca sabe como o projeto pode mudar ao longo do tempo. Hashes de commit são mais confiáveis porque não podem ser alterados
2. Optional dependencies#
Dependências opcionais (também chamadas de dependências de feature) podem ser instaladas pelos usuários conforme necessário. Dependências opcionais adicionam funcionalidades específicas ao seu pacote que nem todos os usuários precisam. Por exemplo, se seu pacote tiver uma funcionalidade opcional de gráficos interativos usando Bokeh, você listaria o Bokeh como um [project.optional-dependencies]. Usuários que quiserem gráficos interativos irão instalá-lo. Usuários que não precisarem de gráficos não precisam instalá-lo.
Coloque essas dependências na tabela [project.optional-dependencies].
[project]
...
...
...
[project.optional-dependencies]
plot = ["bokeh"]
Quando um usuário instala seu pacote, uv, pip ou conda instalam automaticamente todas as dependências obrigatórias. Dependências opcionais só são instaladas se o usuário solicitá-las explicitamente.
How to Add Optional Dependencies Using UV
Você pode usar uv para adicionar dependências ao seu arquivo pyproject.toml:
Adicionar uma dependência opcional:
uv add --optional feature pandas
Will add this to your pyproject.toml file:
[project.optional-dependencies]
feature = [
"pandas>=2.3.3",
]
3. Dependency groups#
Dependências de desenvolvimento incluem pacotes necessários para trabalhar localmente no seu pacote. Elas são usadas para executar tarefas como:
executar sua suíte de testes (pytest, pytest-cov)
gerar sua documentação (sphinx, pacotes de sphinx-theme)
linting e formatação de código (ruff, black)
gerar arquivos de distribuição do pacote (build, twine)
Dependency groups are optional because they are not required for users to install and use your package. However, they will make it easier for contributors to your project to set up development environments locally.
New: PEP 735 dependency groups
[dependency-groups] é uma especificação mais nova introduzida pela PEP 735. Ela foi criada para organizar dependências de desenvolvimento e é intencionalmente separada de [project.optional-dependencies], que podem ser instaladas no ambiente do usuário.
Como declarar grupos de dependências#
Você declara dependências de desenvolvimento no seu arquivo pyproject.toml dentro de uma tabela [dependency-groups].
Assim como em optional-dependencies, você pode criar subgrupos separados ou arrays nomeados usando a sintaxe: group-name = ["dep1", "dep2"]
[dependency-groups]
test = [
"pytest",
"pytest-cov"
]
lint = [
"black",
"flake8",
"ruff"
]
docs = [
"sphinx",
"pydata-sphinx-theme"
]
dev = [
{include-group = "test"},
{include-group = "lint"}
]
Como adicionar [dependency-groups] usando UV
Você pode usar uv para adicionar dependências ao seu arquivo pyproject.toml:
Adicionar uma dependência de grupo de desenvolvimento:
uv add --group tests pytest
uv add --group docs sphinx
Irá adicionar o seguinte ao seu arquivo pyproject.toml:
[dependency-groups]
tests = [
"pytest>=8.4.2",
]
docs = [
"sphinx>=8.1.3",
]
Entendendo dependências obrigatórias vs. opcionais#
Dependências de pacotes Python se dividem em duas categorias: dependências obrigatórias, que usuários precisam para executar seu pacote, e dependências opcionais para desenvolvimento ou funcionalidades adicionais.#
Recursos adicionais sobre dependências
Instalar grupos de dependências#
Quando alguém instala seu pacote, apenas as dependências principais são instaladas por padrão. Para instalar dependências opcionais, você precisa especificar quais grupos incluir durante a instalação do pacote.
When a user installs your package using pip install your-package, only
your package and its core dependencies get installed. When they install
with pip install your-package[tests], pip will install your package,
core dependencies, and the test dependencies from the
[project.optional-dependencies] field.#
Usando uv ou pip para instalação#
O UV simplifica esse processo, permitindo sincronizar uma venv no diretório do seu projeto com uma instalação editável do seu pacote e suas dependências automaticamente. Você também pode usar pip e instalar dependências no ambiente de sua escolha.
Instalar grupos de desenvolvimento:
Você pode usar uv sync para sincronizar grupos de dependências na sua venv gerenciada pelo uv
uv sync --group docs # Single group
uv sync --group docs --group test # Multiple groups
uv sync --all-groups # All dependency groups
Dica
use --active with uv sync to prefer the currently active virtual environment over the project’s own managed environment:
$ uv sync --active --group docs
Instalar dependências opcionais:
# uv pip install is not ideal if you are using uv supported venvs for your project
$ uv pip install -e ".[docs]" # Single group
$ uv pip install -e ".[docs,tests,lint]" # Multiple groups
Dica
Use the --active flag with uv run to prefer the currently active
virtual environment over the project’s own managed environment:
$ uv run --active pip install -e ".[docs]"
This is useful when you have activated a virtual environment and want
uv run to use it instead of automatically creating or selecting the
project’s environment.
Instalar tudo (pacote + todas as dependências):
uv sync --all-extras --all-groups
uv sync é o comando recomendado para workflows de desenvolvimento. Ele gerencia seu ambiente virtual e mantém seu lockfile atualizado. Use uv pip install quando precisar de compatibilidade com comportamento do pip.
Instalar dependências opcionais:
python -m pip install -e ".[docs]" # Single group
python -m pip install -e ".[docs,tests,lint]" # Multiple groups
Instalar grupos de desenvolvimento:
python -m pip install --group test # Single group
python -m pip install --group docs # Multiple groups
Sempre execute pip usando python -m pip para garantir que você está usando o pip do seu ambiente Python atualmente ativo. Isso ajuda a evitar conflitos de instalação.
Nota: Alguns shells (como zsh no Mac) exigem aspas ao redor dos colchetes para executar corretamente:
python -m pip install ".[tests]"
Combinando grupos de dependências#
Você também pode criar grupos combinados que referenciam outros grupos:
[project.optional-dependencies]
plot = ["bokeh"]
test = ["pytest", "pytest-cov"]
docs = ["sphinx", "pydata-sphinx-theme"]
Depois instale tudo com pip install ou uv sync conforme necessário:
uv pip install -e ".[dev]"
# or
python -m pip install ".[dev]"
Dica
When you install optional dependencies, pip and uv install your package and its core dependencies automatically.
Especificadores de versão para dependências#
Especificadores de versão controlam quais versões de uma dependência funcionam com seu pacote. Use-os para especificar versões mínimas, excluir releases com bugs ou definir intervalos de versão.
Operadores comuns#
>=Versão mínima:numpy>=1.20(Esta é a abordagem mais comum e recomendada)==Versão exata:requests==2.28.0(Evite fixar dependências assim, a menos que seja necessário)~=Release compatível:django~=4.2.0(Permite patches: >=4.2.0,<4.3.0)<ou>- Limites superior/inferior:pandas>=1.0,<3.0!=Excluir versão:scipy>=1.7,!=1.8.0(Raro, mas permite ignorar uma versão release com bugs)
Dica
Boa prática: Use >= para especificar sua versão mínima testada e evite limites superiores a menos que você saiba em qual versão aquela dependência deixa de ser compatível. O UV faz isso por padrão quando adiciona uma dependência ao seu arquivo pyproject.toml. Isso mantém seu pacote flexível e reduz conflitos de dependências.
dependencies = [
"numpy>=1.20", # Good - flexible
"pandas>=1.0,<3.0", # OK - known breaking change in 3.0
"requests==2.28.0", # Avoid - too restrictive
]
O arquivo pyproject.toml funciona muito bem para pacotes Python puros. Porém, alguns pacotes (principalmente no ecossistema científico Python) precisam de dependências escritas em outras linguagens como C ou Fortran. O Conda foi criado para suportar a distribuição de ferramentas com dependências não-Python.
Para usuários de conda:
Você pode manter um arquivo environment.yml para ajudar usuários e contribuidores a configurarem ambientes conda. Isso é especialmente útil para pacotes com dependências de sistema como GDAL.
Considere o Pixi para workflows focados em pacotes conda:
Pixi é um gerenciador de pacotes moderno construído em cima dos ecossistemas conda e de pacotes Python. O Pixi consegue tratar requisitos de pacotes conda e Python de forma equivalente ao resolver ambientes, mas usa uma abordagem «conda-first», utilizando pacotes conda já resolvidos sempre que possível ao resolver dependências Python. O Pixi também pode usar pyproject.toml para configuração. Se seu projeto depende fortemente de pacotes conda, o Pixi oferece um workflow simplificado com resolução de dependências mais rápida e suporte automático a lock files para reprodutibilidade completa do ambiente. Se você já possui um arquivo de definição de ambiente conda, como um environment.yml, pode importar o ambiente para um novo workspace Pixi com
pixi init --import environment.yml
Uma observação para usuários de conda
Se você usa um ambiente conda para desenvolvimento e instala seu pacote com python -m pip install -e ., as dependências serão instaladas a partir do PyPI, potencialmente sobrescrevendo pacotes conda que já haviam sido instalados. Isso pode causar conflitos, especialmente em pacotes com dependências de sistema.
Para evitar isso, instale seu pacote sem dependências:
python -m pip install -e . --no-deps
Depois instale as dependências através do seu arquivo conda environment.yml.
Dependências no Read the Docs#
Depois de especificar dependências no seu pyproject.toml, você pode usá-las em outros workflows, como gerar documentação no Read the Docs.
Read the Docs é uma plataforma de documentação que gera e publica automaticamente sua documentação. Para instalar suas dependências durante o processo de build, configure-as em um arquivo readthedocs.yaml.
Aqui está um exemplo que instala suas dependências opcionais docs:
python:
install:
- method: pip
path: .
extra_requirements:
- docs
Saiba mais sobre o Read the Docs
Dependency Locking#
In addition to declaring dependencies in pyproject.toml, it is common for
packages to lock down exact versions of all their dependencies in a separate
lock file. A lock file provides benefits of reproducibility, security, and
potentially faster installs, among other things. Pinning the exact dependency
versions used in a project eliminates «works on my machine» bugs and gives CI a
reproducible baseline. For applications meant to be run rather than imported,
lock files also ensure anyone installing the project gets a known-good set of
dependencies instead of whatever happens to be latest.
pyproject.toml vs lock file#
pyproject.toml: defines all environments you intend to support for users importing your package into their project.lock file: defines a specific environment used for development
pyproject.toml should be permissive, erring on the side of allowing too much
even if it may allow untested environments. In most cases, it is better that
users install your package but encounter an issue rather than being restricted
from installing your package by the pyproject.toml when it would otherwise
work.
A lock file is the opposite. If it installs, the resulting environment should work even if this means some valid environments are excluded.
Standardized Lock File
As of March 2025, PEP 751 defined a standard
pylock.toml format to unify the various lock file formats in use by other
package managers (e.g. uv.lock, poetry.lock, pdm.lock). Most package
managers provide ways to generate a PEP 751 compatible file. See PyPA
specification
for up-to-date formatting info on pylock.toml
How to work with lock files?#
Lock files are not written by hand. Package managers and IDEs provide tools to create, update, and reformat lock files as needed.
Create - Package managers often do this automatically though it can be done manually. For example, calling
uv add numpywill automatically create auv.lockfile, setup the environment, and install numpy.Update - This is not done automatically by package managers. Maintainers can choose to do this manually or setup their own automated workflow. Updates can be for specific packages or all dependencies.
Reformat - Package managers currently use native formats (e.g. uv uses
uv.lock) and provide tools for converting intopylock.tomland other formats (e.g.requirements.txt) when needed
Below is the uv CLI workflow for lock files:
# Create a uv.lock file based on pyproject.toml
> uv lock
# Update uv.lock
> uv lock --upgrade
> uv lock --upgrade-package pandas
# Install packages into environment based on uv.lock
> uv sync
# PEP 751 pylock.toml support
> uv export --format pylock.toml -o pylock.toml # export uv.lock -> pylock.toml
> uv pip sync pylock.toml # install from pylock.toml
See official docs for more details. See also the relevant docs for Poetry and PDM.
Should I use a lock file?#
Most package managers will generate a lock file automatically for you (e.g. uv, Poetry, PDM). The real question is when you version control the lock file as part of your package.
Recommendation: Versioning a lock file
If your project is an application others use directly, include a lock file as the recommended environment.
If your project is a library to be used in other projects and it is mature enough to have CI, include a lock file for CI and contributors. For a small library only you maintain that is shared amongst people you know, waiting to add a lock file is not an issue. In general, you should version the lock file.
For private libraries shared within a team, a lock file is less important. But if the project is an application or tool that others run directly, instead of importing into their code, committing the lock file is generally the most convenient choice. It gives users a reproducible set of dependencies instead of having each user resolve from pyproject.toml.
Recommendation: Which format to version control
Version control the standard pylock.toml format.
There is some maintenance cost from lock files. Maintainers should aim to update the lock file neither too rarely nor too often.
Too rarely means you risk missing updates with bugfixes, security patches, performance improvements, etc.
Too often means you may introduce bugs or even security vulnerabilities before maintainers of your dependencies catch them. Package managers are starting to support dependency cooldowns to mitigate this.
Recommendation: Updating a lock file
Update lock files frequently (e.g. weekly) but configure a dependency cooldown of several days to avoid automatically installing the latest packages. Only override the cooldown if a new package has a needed bug fix or security patch.
Dependency cooldowns
Dependency cooldowns are strongly encouraged by security experts to avoid automatically downloading the latest package updates that may have been compromised with malware. Package manager tools are starting to support configurations for cooldowns
> uv lock --exclude-newer "3 days"`
or in pyproject.toml
[tool.uv]
exclude-newer = "3 days"
Integrating cooldown constrained lock files into CI is important since this is
where new packages are commonly tested first. Automated testing code that
resolves [project.dependencies] every time
> python -m pip install .
can be replaced with lock file based installations
> uv pip sync pylock.toml
after pylock.toml has been added to the project.
> uv lock --exclude-newer "3 days"`
> uv export --format pylock.toml -o pylock.toml
Support for this varies across automated testing frameworks (e.g. hatch, nox) so consult their documentation for how to install dependencies from lock files with dependency cooldowns.
When you decide to update a lock file, make sure to test that the resulting
environment works before committing. If it fails because of some dependency
update, then it may be necessary to update pyproject.toml to cap the supported
versions of that dependency unless/until the code can be updated to support it.
It can also be good, though not necessary, to double check what changed when updating a lock file. The diff can be noisy so the main changes to focus on are
major version updates (e.g.
pandas 2.X.X->pandas 3.X.X)new transitive dependencies (i.e. not part of your
pyproject.toml)
Dica
A lock file captures one environment for CI testing, not the full compatibility
range declared in pyproject.toml. Projects that use lock files may want to
have CI test other environments such as
the latest packages consistent with your
pyproject.toml, subject to dependency cooldowns. This lets you know if a dependency update breaks your package.older supported versions of Python to let you know if a recent change to your package no longer works with an older Python release.
What about requirements.txt
Older approaches to locking used pip freeze to generate a requirements.txt
that got used as a lock file. These are minimal lock files that pin a specific
version for the system on which the command was run. They might look like
# requirements.txt
numpy==2.4.6
plotly==6.7.0
pyzmq==27.1.0
However, this minimal level of specificity has several downsides making lock files the preferred format:
The versions satisfying
pyproject.tomlmay differ between your Windows laptop and the Linux server your CI runs on. A single lock file contains the information needed to build platform specific and Python version specific environments. In contrast, a separaterequirements.txtfiles is needed to store this information (e.g.requirements.ci.txt,requirements.py313-macos.txt)Packages can get updated without a version update for both legitimate and malicious reasons. Lock files include package hashes to catch this. A hash is a unique signature computed from the code and any change to the code will cause the release to have a different hash even if is given the same release version number.
Other metadata determined during resolution of
pyproject.toml(e.g. which dependencies are transitive, where the packages were downloaded from, etc.) that can help speed up future installs is lost.