Path.copy() amplia a API orientada a objetos do pathlib para copiar arquivos e árvores de diretórios sem sair da abstração de caminhos. Em vez de converter objetos Path para strings e alternar entre vários módulos, você pode manter a lógica de navegação, validação e cópia em uma interface única. Isso torna scripts de backup, ferramentas de build, instaladores, migrações e rotinas de organização de arquivos mais legíveis.
Este guia explica o comportamento esperado, os cuidados com sobrescrita, links simbólicos, metadados, permissões, erros parciais e testes. O foco não é apenas a sintaxe, mas como usar a operação de forma previsível em projetos reais.
O que Path.copy faz
A ideia central é copiar o caminho atual para um destino informado. Quando a origem é um arquivo, o conteúdo é replicado no destino. Quando é um diretório, a operação pode percorrer a árvore e criar a estrutura correspondente. A API reduz código cerimonial e deixa claro que a ação pertence ao próprio caminho.
Mesmo com uma interface simples, copiar arquivos envolve decisões importantes: o destino existe, deve ser substituído, links devem ser seguidos, permissões precisam ser preservadas e o sistema de arquivos aceita os mesmos recursos? Essas perguntas precisam ser respondidas antes de usar a função em produção.
Exemplo básico
from pathlib import Path
origem = Path("dados/relatorio.csv")
destino = Path("backup/relatorio.csv")
destino.parent.mkdir(parents=True, exist_ok=True)
resultado = origem.copy(destino)
print(resultado)
Crie o diretório pai explicitamente quando necessário. Isso evita depender de comportamento implícito e facilita a validação. Guarde o caminho retornado para registrar logs, executar verificações ou continuar o processamento.
Copiando diretórios
Para árvores de diretórios, confirme se a versão do Python e o sistema suportam o comportamento desejado. Uma cópia recursiva deve preservar a estrutura, mas não deve ser tratada como transação atômica. Se a operação falhar no meio, parte dos arquivos pode ter sido criada. Portanto, use um diretório temporário e faça a troca final somente após verificar o resultado quando a consistência for importante.
from pathlib import Path
import tempfile
origem = Path("site")
destino = Path("dist/site")
with tempfile.TemporaryDirectory(dir=destino.parent) as temp:
temporario = Path(temp) / "site"
origem.copy(temporario)
if destino.exists():
raise FileExistsError(destino)
temporario.replace(destino)
Esse padrão reduz o risco de deixar um destino oficialmente válido, porém incompleto.
Sobrescrita e conflitos
Não presuma que o destino será substituído. Verifique a documentação da versão usada e implemente uma política explícita. Em backups, normalmente é melhor gerar nomes versionados. Em builds reproduzíveis, pode ser aceitável remover uma pasta anterior após confirmar que ela pertence ao processo atual. Em dados do usuário, sobrescrita silenciosa deve ser evitada.
def copiar_sem_substituir(origem: Path, destino: Path) -> Path:
if destino.exists():
raise FileExistsError(f"Destino já existe: {destino}")
destino.parent.mkdir(parents=True, exist_ok=True)
return origem.copy(destino)
Evite o padrão de testar e copiar em ambientes concorrentes sem proteção, porque outro processo pode criar o destino entre as duas operações. Quando houver concorrência real, use diretórios exclusivos, locks ou nomes aleatórios.
Links simbólicos
Links simbólicos exigem uma decisão de segurança. Seguir o link copia o conteúdo apontado; preservar o link mantém a referência. Em entradas não confiáveis, seguir links pode levar a arquivos fora da árvore esperada. Resolva caminhos com cuidado, imponha uma raiz permitida e rejeite destinos que escapem dela.
raiz = Path("entrada").resolve()
origem = Path("entrada/item").resolve()
if raiz not in origem.parents and origem != raiz:
raise ValueError("Origem fora da raiz permitida")
Essa checagem ajuda, mas condições de corrida ainda podem existir em sistemas onde links mudam durante a operação.
Metadados e permissões
Conteúdo, timestamps, modo de acesso, ACLs, atributos estendidos e proprietário não são a mesma coisa. Uma cópia pode preservar alguns metadados e perder outros, especialmente entre sistemas de arquivos diferentes. Se a fidelidade for crítica, teste no ambiente alvo e valide explicitamente os atributos importantes.
Também considere o princípio do menor privilégio. Um arquivo copiado não deve herdar permissões mais amplas do diretório de destino sem revisão. Para segredos, ajuste o modo depois da cópia e nunca registre o conteúdo em logs.
Tratamento de erros
Capture erros específicos como FileNotFoundError, PermissionError, FileExistsError e OSError. Registre origem, destino e etapa, mas evite expor caminhos sensíveis a usuários finais.
try:
origem.copy(destino)
except FileNotFoundError:
print("A origem não existe")
except PermissionError:
print("Permissão insuficiente")
except OSError as erro:
print(f"Falha no sistema de arquivos: {erro}")
Para lotes, decida se um erro interrompe tudo ou se os demais itens continuam. Produza um relatório final com sucessos e falhas.
Desempenho
O desempenho depende do tamanho dos arquivos, latência do disco, cache, rede e implementação do sistema operacional. Evite ler todo o conteúdo em memória apenas para copiar. Para grandes volumes, meça throughput e espaço livre antes de iniciar. Em destinos remotos, implemente retentativas apenas para erros transitórios e nunca repita cegamente uma operação parcialmente concluída.
Validação após a cópia
Para dados comuns, tamanho e existência podem ser suficientes. Para artefatos críticos, calcule hashes na origem e no destino. Isso custa I/O adicional, mas detecta corrupção ou cópias incompletas.
import hashlib
def sha256(caminho: Path) -> str:
digest = hashlib.sha256()
with caminho.open("rb") as arquivo:
for bloco in iter(lambda: arquivo.read(1024 * 1024), b""):
digest.update(bloco)
return digest.hexdigest()
Compatibilidade entre versões
Antes de adotar Path.copy, confirme a versão mínima do Python do projeto. Bibliotecas distribuídas para ambientes antigos podem oferecer um fallback com shutil. Centralize essa compatibilidade em uma função para não espalhar condicionais pelo código.
def copiar(origem: Path, destino: Path) -> Path:
if hasattr(origem, "copy"):
return origem.copy(destino)
import shutil
if origem.is_dir():
return Path(shutil.copytree(origem, destino))
return Path(shutil.copy2(origem, destino))
Testes recomendados
Teste arquivo pequeno, arquivo vazio, diretório aninhado, destino existente, falta de permissão, link simbólico, nomes Unicode, caminhos longos, disco cheio e interrupção durante a cópia. Use tempfile.TemporaryDirectory para isolar os testes. Em integração, execute nos sistemas operacionais suportados.
Boas práticas
Valide a origem, crie o pai do destino, defina uma política de sobrescrita, controle links simbólicos, trate cópias recursivas como não atômicas, verifique espaço livre, registre resultados e valide arquivos críticos. Não aceite caminhos arbitrários de usuários sem limitar a raiz permitida.
Veja também pathlib no Python, shutil no Python, arquivos no Python e tratamento de erros. Consulte a documentação oficial do pathlib e a documentação do shutil.
Conclusão
Path.copy torna operações de cópia mais coerentes com o estilo moderno do pathlib. A simplicidade da chamada não elimina decisões sobre segurança, consistência, metadados e compatibilidade. Encapsule a política de cópia, teste em múltiplas plataformas e use validação proporcional à importância dos dados.







