14 pontos por GN⁺ 2025-06-25 | 2 comentários | Compartilhar no WhatsApp
  • Com o gerenciador de pacotes uv e a PEP 723, agora é possível executar scripts Python sem problemas de dependências
  • O recurso uvx cria automaticamente ambientes virtuais descartáveis, resolvendo a inconveniência da configuração manual do ambiente
  • Ao incluir metadados da PEP 723 no arquivo Python, a execução automática do script e o gerenciamento de pacotes se tornam mais práticos
  • Como exemplo de script executável, é possível implementar e distribuir rapidamente um programa de extração de legendas do YouTube
  • Com isso, o Python agora também passa a permitir a criação concisa de arquivos executáveis únicos, ampliando bastante a utilidade dos scripts

Visão geral

  • No Python, a inconveniência de ter que configurar o ambiente e instalar pacotes toda vez ao executar um "script pontual (one-off)" desaparece com a adoção de uv e PEP 723
  • O uv é um gerenciador de pacotes e projetos Python de alta velocidade desenvolvido em Rust e, com o novo recurso uvx, lida de forma muito rápida e simples com a criação de ambientes virtuais descartáveis, instalação automática de pacotes e vinculação da versão do Python

Vantagens do uv e do uvx

  • O recurso uvx funciona de forma semelhante ao npx do ecossistema Nodejs, criando rapidamente um ambiente de execução para o pacote Python especificado (ex.: ruff)
  • Usa ambientes virtuais descartáveis em cache, oferecendo execução rápida sem overhead
  • A configuração do ambiente e a instalação de dependências são feitas com uma única linha de comando, sem exigir que o desenvolvedor gerencie a configuração manualmente

Introdução e uso da PEP 723

  • A PEP 723 define um padrão para incluir metadados de dependências e ambiente no topo de scripts Python
  • Exemplo: é possível declarar requires-python, dependencies etc. no início do código
  • Ferramentas externas que reconhecem isso (como o uv) cuidam automaticamente da instalação, da configuração do ambiente e da execução com base nas informações escritas no próprio arquivo do script

A combinação de uv com PEP 723

  • Ao escrever esses metadados no topo de um arquivo Python real e executá-lo com o comando run do uv, todos os pacotes necessários são instalados automaticamente, a versão de Python especificada é configurada e então o código é executado
  • O código de exemplo chama uma API da internet (lista de PEPs) e exibe o resultado. Tudo pode ser executado com uma única linha, sem necessidade de instalar pacotes extras nem configurar o ambiente

Exemplo prático: script de legendas do YouTube

  • É apresentado um exemplo de script Python com shebang (#!/usr/bin/env -S uv run --script) e metadados da PEP 723 adicionados
  • Pacotes externos como youtube-transcript-api são instalados automaticamente, e a configuração do ambiente virtual também é feita de forma automática
  • O usuário pode passar a URL ou o ID de um vídeo do YouTube como argumento ao executável (ytt), e as legendas são extraídas com o resultado fornecido imediatamente
  • Após conceder permissão de execução com chmod, o script pode ser executado de forma simples no terminal

Melhoria na experiência do desenvolvedor e expansão das possibilidades

  • Antes, mesmo para executar scripts simples, muitas vezes se preferiam linguagens que geram binários executáveis únicos, como Go; agora, o Python também oferece um nível semelhante de praticidade
  • A combinação de uv e PEP 723 torna muito mais fácil compartilhar, distribuir e automatizar a execução de scripts Python
  • Casos de uso mais complexos também podem ser desenvolvidos com base no exemplo no GitHub (cottongeeks/ytt-mcp)

2 comentários

 
ndrgrd 2025-06-25

O uv é absurdamente rápido, então gostei bastante. Hoje em dia estou usando uv em todos os lugares possíveis.

 
GN⁺ 2025-06-25
Comentários do Hacker News
  • Assim como o autor do texto, ultimamente tenho recorrido mais a one-offs em Python multiplataforma e scripts pessoais do que a Go, mas sigo insatisfeito com o fato de o sistema de checagem de tipos do Python ser um caos completo; espero que ferramentas como ty e pyrefly melhorem isso nem que seja um pouco

  • Agora parece que scripts em Python finalmente funcionam direto sem fazer a gente sofrer por causa de virtualenv Seria ótimo ter uma experiência parecida também com shell script Empacotamento, gerenciamento de dependências e reprodutibilidade ainda estão na Idade da Pedra Ainda é aquela realidade de confiar na sorte com curl | bash, ou ter só um README com 3 dependências faltando e 12 etapas manuais Nix? Parece uma opção útil só para quem já transcendeu tempo, espaço e o manual do Nix Docker? Tudo bem, se baixar uma distro Linux para rodar um único comando sed parece razoável para você Faz falta um meio-termo simples e declarativo que qualquer pessoa consiga usar

    • Eu prefiro escrever apenas shell scripts que usam binários e bibliotecas já embutidos no SO de destino A meta de tornar shell script portável é, na prática, uma escolha que não combina muito Se você precisa rodar no Linux um shell script que usa comandos específicos do macOS, isso é um problema que nenhum gerenciador de pacotes resolve
    • Nix não parece tão difícil de usar para esse objetivo Compartilharam um exemplo de como dá para usar de forma simples assim ao instalar Nix em outra distro NixOS e o empacotamento completo do Nix são bem desafiadores, mas para shell script a barreira de entrada é relativamente baixa
    • Não vejo muita necessidade de escrever novos shell scripts de propósito Se você está em um ambiente onde é permitido instalar todas as dependências, uma ferramenta como uv resolve tudo Se você gosta de Clojure, também recomendo babashka
    • O motivo de empacotamento, gerenciamento de dependências e reprodutibilidade em shell script parecerem coisa de outra era é que, se você precisa disso tudo, provavelmente shell não é a ferramenta adequada Minha posição é que shell só combina com scripts pequenos, de umas 20 linhas A linguagem em si não tem qualidade suficiente para algo maior que isso
    • Recomendo mise Uso na empresa para gerenciar ambientes de desenvolvimento, e ele permite montar o ambiente com muito mais simplicidade do que Docker e Nix O suporte a instalação em paralelo é uma vantagem enorme em relação a um Dockerfile comum
  • É uma tendência muito legal e parece estar ficando cada vez mais popular Vi isso primeiro no blog do simonw, e dá para conferir mais no post do blog de simonwillison Em março deste ano também houve uma discussão no Hacker News sobre outro post de blog Tomara que essa tendência fique bastante tempo na página principal para que mais gente perceba

  • Testei uv em um projetinho e a experiência foi excelente A combinação de uv run e uv tool run (uvx) torna extremamente simples instalar e executar direto em uma VM scripts Python hospedados no GitHub Não precisa de git clone, nem criar ou entrar em venv, nem de pip install Acima de tudo, o uv é tão rápido que no começo parece até que algo está errado; na prática, ele entrega algo 10 vezes mais rápido que o pip As ferramentas e a documentação ainda estão um pouco inacabadas, mas o nível de inovação e utilidade já torna tudo isso bem aproveitável

    • Sinceramente, fico impressionado que o uv instale dependências mais rápido do que o pyenv leva para imprimir --help
  • Rust também está evoluindo uma ideia parecida de shell script tipado em arquivo único Foi no Rust que vi esse estilo pela primeira vez (suporte para executar um único arquivo com gerenciamento de dependências embutido) Espero que esse padrão se estabeleça em mais linguagens, porque é muito útil para compartilhar via gist ou criar ferramentas pequenas e rápidas Veja também o documento RFC do cargo-script

  • Ao usar uv run --script, incluir os metadados no script deixa um pouco incômodo abrir um REPL Python diretamente a partir dele para testar modificações Por exemplo, seria preciso fazer algo assim:

    $ uv run --python=3.13 --with-requirements <(uv export --script script.py) -- python
    >>> from script import X
    

    Seria ótimo se houvesse uma forma mais concisa Por exemplo,

    $ uv run --with-script script.py python
    

    seria o ideal, mas na prática, se executar o seguinte, dá para entrar direto no Python e no ambiente venv correspondente ao script:

    $ "$(uv python find --script script.py)"
    >>> from script import X
    

    Mas é preciso executar o script ao menos uma vez para criar o ambiente

    • Se você precisa de uma função para chamar o REPL depois do setup, recomendo este exemplo de gist Dá para transformar isso em opção de CLI colocando algo como uma flag --interactive no script Costumo escrever pequenos CLIs com Typer dessa forma Em scripts de dev, já usei uma flag --sql para entrar em um REPL SQL do DuckDB
    • Uma forma simples apresentada:
      cat ~/.local/bin/uve
      #!/bin/bash
      temp=$(mktemp)
      uv export --script $1 --no-hashes > $temp
      uv run --with-requirements $temp vim $1
      unlink $temp
      
  • Se você usa conda, dá para ativar o ambiente diretamente em um wrapper shell para scripts Python Ficaria assim:

    #!/usr/bin/env bash
    eval "$(conda shell.bash hook)"
    conda activate myenv
    python myscript
    

    Ainda assim, é uma abordagem que não é independente como o estilo do PEP 723

  • Depois de ver a thread do HN ontem e hoje, resolvi experimentar uv pela primeira vez e fiquei muito impressionado com a velocidade e a facilidade de gerenciar dependências A documentação oficial ficaria ainda melhor com melhorias, especialmente se houvesse um guia de migração de workflows com requirements.txt para uv A forma de definir a versão de Python por projeto também é confusa (.python-version e pyproject.toml definidos em dois lugares)

    • Tenho experiência escrevendo um ebook exploratório sobre ferramentas de desenvolvimento Python Já cobri partes que a documentação oficial deixa em aberto, então recomendo: como migrar de requirements.txt e como mudar a versão de Python de um projeto uv Se houver outros temas que você gostaria que fossem abordados, fique à vontade para sugerir
    • O campo requires-version em pyproject.toml indica a faixa de versões com compatibilidade garantida, enquanto .python-version especifica a versão exata usada no desenvolvimento Quando você cria com uv init, no começo os dois parecem iguais, mas com o tempo requires-version passa a indicar uma versão mínima suportada mais baixa do que .python-version requires-version também entra nos metadados do pacote e afeta a resolução de dependências para outras pessoas que usam o pacote distribuído Por exemplo, quando a v1 ainda suporta uma versão antiga do Python, mas a v2 já não
    • Tenho uma sensação parecida, mas insisto no meu próprio workflow (sincronizar o mesmo arquivo via Dropbox em todos os computadores e usá-lo independentemente da plataforma) Em npm ou dotnet, ao mudar de plataforma você precisa de npm update ou dotnet restore, mas a venv continua funcionando sem problemas Já com uv, ao trocar de plataforma parece haver mais complexidade e necessidade de limpeza manual
    • pyproject.toml serve (independentemente do uv em si) para definir o ambiente necessário ao compartilhar código com desenvolvedores e usuários externos Ele informa qual ambiente é necessário ao construir um pacote para o PyPI, e a faixa de versões também é configurada para ampliar o leque de reutilização do código por várias pessoas .python-version é usado apenas pelo uv e apenas quando ele configura meu ambiente de desenvolvimento Se você já tiver um ambiente pronto, não há problema em não configurar isso novamente O uv ainda não é um backend oficial de build, mas está se preparando para isso (issue #3957)
    • Nunca investiguei a fundo, mas imagino que o papel do arquivo .python-version seja basicamente compatibilidade com outras ferramentas que não têm parser TOML
  • Há algum tempo tive vontade de criar uma ferramenta que fizesse scripts Python instalarem sozinhos suas dependências (a ideia era algo que funcionasse como uvx, mas rodando só com Python instalado) O problema é que seria preciso colocar várias linhas estranhas no começo do script Se tiver curiosidade, publiquei isso no PyPI com o nome pysolate

    • Existe também o projeto isolate, parecido, mas não muito difundido A abordagem é um pouco diferente, mas é um caso interessante
  • Uma mensagem no estilo Grace Hopper, inspirada em COBOL Todo programa Python deveria definir uma ENVIRONMENT division para deixar claro o ambiente de compilação e execução, incluindo requisitos de hardware e software A ideia é que esse tipo de estrutura teria impacto decisivo para melhorar a portabilidade de programas entre sistemas diversos