Definir a chamada como uma interface
Antes de chamar uma ferramenta, escreve o contrato: executável, argumentos, diretoria, ambiente, dados de entrada e resultados esperados. Num programa nativo POSIX, uma lista de argumentos com shell=False permite passar report final.csv como um argumento, sem construir uma linha para o shell interpretar. Isto não valida as opções da ferramenta nem autoriza qualquer caminho recebido. Confirma ainda o intérprete e as dependências usados pelo scheduler. Ao fornecer env, estás a substituir a herança implícita por um mapping; escolhe deliberadamente as chaves necessárias. Uma execução no terminal só serve de comparação se essas condições forem equivalentes.
Distinguir arranque, saída e prazo
Um wrapper tem várias fronteiras de falha. Não encontrar um executável pode levantar OSError; receber um código não zero com check=True pode levantar CalledProcessError; ultrapassar o prazo pode levantar TimeoutExpired. Guarda uma categoria útil e uma referência de execução, sem despejar argumentos ou saídas sensíveis. Com check=False, examina returncode: a existência de CompletedProcess não prova sucesso. Em POSIX, um valor negativo identifica término por sinal, mas não o emissor. Mesmo um código zero só satisfaz a etapa de execução. Se o contrato exige 240 operações únicas e existem 239, a entrega não está completa.
Gerir pipes, memória e descodificação
Quando o filho escreve em PIPE e o pai espera sem ler, um buffer cheio pode bloquear a conclusão. Drenar apenas stdout também pode deixar stderr a impedir progresso. Para saída pequena e limitada, communicate coordena a leitura e espera; para gigabytes ou saída sem limite, o buffering em memória deixa de ser uma solução adequada. Define armazenamento autorizado, quota, erros de escrita e retenção, ou consumo incremental devidamente limitado. Decide também a codificação. Se o contrato exige UTF-8 válido, errors="replace" pode ocultar bytes inválidos e alterar os dados. Uma mensagem legível não demonstra uma entrega fiel.
Resolver um timeout sem abandonar trabalho
Conhece a API concreta antes de desenhar recuperação. run trata a expiração matando e esperando pelo filho direto; communicate num Popen não mata automaticamente o filho quando o prazo expira. Neste segundo caso, observa o estado e aplica o procedimento previsto para terminar ou continuar a comunicação. A criação inicial de processos também pode afetar o tempo até à exceção. Nenhum destes contratos garante rollback dos efeitos externos ou terminação automática de toda a árvore criada. Guarda identidade e artefactos parciais e reconcilia o resultado antes de repetir. O scheduler deve distinguir prazo excedido de conclusão e de resultado ainda incerto.
Tratar o caminho como acesso a um objeto
Um teste textual de caminho não equivale a autorização sobre o objeto aberto. PurePath.is_relative_to não consulta o filesystem nem resolve componentes ..; um prefixo aparentemente correto pode ser enganador. Resolver o caminho ajuda a observar o destino naquele instante, mas não bloqueia mudanças de symlinks antes da abertura. Controla quem pode alterar a área e escolhe mecanismos adequados à plataforma e ao modelo de acesso. Para temporários, prefere APIs que criem o objeto em vez de devolver apenas um nome para utilização posterior. Define dono, limpeza, limites e publicação. Estes exercícios identificam fronteiras; não fornecem uma sandbox completa de ficheiros.
import subprocess
import sys
result = subprocess.run(
[sys.executable, "-I", "-c", "import sys; print(sys.argv[1])",
"report final.csv"],
check=True, capture_output=True, encoding="utf-8", timeout=3,
)
print(result.stdout.strip())Exercício local sem rede: um filho Python imprime apenas o argumento report final.csv. Confirma que recebe um argumento, que stdout é texto e que o wrapper trata estado não zero se alterares o filho num ensaio separado. Este exemplo não executa comandos fornecidos por utilizadores.
Armadilhas comuns
Construir comandos por concatenação; abandonar stderr; capturar gigabytes; confundir run com communicate; tratar caminhos resolvidos como locks; repetir efeitos incertos com nova identidade.
Tópicos relacionados: Funções pequenas, contratos claros · Erros e ficheiros com contexto · Precisão, dados externos e tempo · Automação observável e repetível
O wrapper só comunica sucesso quando execução, recursos e resultado satisfazem o contrato; uma chamada que terminou é apenas uma parte da evidência.
Referência: Python3.14: Subprocess management · Python 3.14; DR Python 2026.3