O uv é uma ferramenta de instalação de pacotes que se destaca pela sua velocidade, superando o pip em uma ordem de magnitude. Embora o argumento predominante seja que "é escrito em Rust", isso não explica totalmente a questão. Diversas ferramentas também são desenvolvidas em Rust sem a mesma eficiência. O que realmente importa são as decisões de design que diferenciam o uv do pip.
As limitações do pip não são fruto de uma má implementação, mas da necessidade de executar código para determinar as dependências de um pacote. O problema central reside no setup.py, pois não é possível saber quais dependências são necessárias sem executar seu script de configuração, o que, por sua vez, requer que as dependências de construção estejam instaladas. Essa situação foi destacada no PEP 518 de 2016, que apontou a falta de um padrão para determinar dependências de forma automatizada.
A solução para esse dilema foi introduzida em várias etapas. O PEP 518 criou o arquivo pyproject.toml, permitindo que pacotes declarem suas dependências de construção sem a necessidade de execução de código. O formato TOML, inspirado no Cargo do Rust, trouxe melhorias significativas ao ecossistema Python. O PEP 517, por sua vez, separou as interfaces de construção, enquanto o PEP 621 padronizou a tabela [project], facilitando a leitura das dependências. O PEP 658, implementado em maio de 2023, também contribuiu ao colocar metadados dos pacotes diretamente na API do repositório.
Além das melhorias de padronização, o uv se destaca pela eliminação de funcionalidades desnecessárias. Por exemplo, ele não oferece suporte a .egg, ignora arquivos de configuração do pip e não compila bytecode por padrão. O uv também exige ambientes virtuais, ao contrário do pip, que permite instalações no Python do sistema. Essas decisões de design resultam em menos caminhos de código que o uv precisa executar, contribuindo para sua rapidez.
Embora algumas otimizações de velocidade do uv sejam atribuídas ao Rust, muitas podem ser implementadas no pip. Por exemplo, o uv realiza downloads paralelos, utiliza um cache global com hardlinks e não depende da execução do Python para resolver dependências, utilizando a análise de metadados TOML e wheel. Além disso, o uv emprega o algoritmo PubGrub, que melhora a resolução de dependências complexas de forma mais eficiente.
Entretanto, algumas vantagens do uv realmente dependem do Rust, como a deserialização sem cópias e a paralelização em nível de thread, que são cruciais para a exploração de combinações de versões. Essas vantagens são significativas, mas as melhorias arquitetônicas e as decisões de design têm um impacto ainda maior.
Em suma, a velocidade do uv é resultado do que ele não faz, mais do que do que a linguagem de programação proporciona. A implementação de padrões como os do PEP 518, 517, 621 e 658 foi fundamental para a gestão de pacotes ágil. O uv demonstra que, ao eliminar suporte a formatos legados e adotar padrões modernos, é possível criar uma ferramenta mais eficiente e rápida. Outras ferramentas de gerenciamento de pacotes podem aprender com isso, adotando metadados estáticos e evitando a execução de código arbitrário para determinar dependências.
Confira os últimos vídeos publicados no canal