ExceptionGroup.split() é um recurso do Python para separar um grupo de exceções em duas partes: as que correspondem a um critério e as que não correspondem. Ele é especialmente útil em aplicações que executam várias tarefas, processam registros em lote ou recebem resultados de diferentes serviços. Nessas situações, mais de uma operação pode falhar ao mesmo tempo, e guardar todas as falhas em um único grupo permite analisar o cenário completo sem perder detalhes importantes.
O que é ExceptionGroup
Um ExceptionGroup reúne várias exceções relacionadas sob uma mesma mensagem. Imagine um processo que valida dezenas de arquivos. Um arquivo pode não existir, outro pode ter permissão insuficiente e outro pode conter dados inválidos. Em vez de interromper tudo na primeira falha, a aplicação pode coletar os problemas e criar um grupo. Assim, cada erro continua disponível para registro, diagnóstico e tratamento.
O recurso foi criado para tornar mais natural o tratamento de falhas em tarefas paralelas e fluxos compostos. Ele também funciona bem em validações, importações, testes e integrações. O objetivo não é esconder exceções, mas organizá-las sem descartar informação.
Como split funciona
O método split() recebe um tipo de exceção, uma tupla de tipos ou uma função de filtro. O retorno é uma tupla com dois elementos. O primeiro contém as exceções que correspondem ao critério. O segundo contém o restante. Quando uma parte não possui itens, o valor retornado para ela é None.
grupo = ExceptionGroup(
"falhas de validação",
[ValueError("idade inválida"), TypeError("tipo incorreto")],
)
valores, outros = grupo.split(ValueError)
Nesse caso, valores contém o ValueError e outros contém o TypeError. A operação não modifica o grupo original. Ela cria novas estruturas derivadas, preservando a mensagem e a organização necessária.
Filtrando mais de um tipo
Também é possível passar uma tupla com vários tipos. Isso ajuda quando diferentes exceções pertencem à mesma categoria prática.
arquivos, restante = grupo.split(
(FileNotFoundError, PermissionError)
)
Essa separação permite tratar falhas de arquivo de uma forma e manter erros de validação ou de programação em outra parte. O resultado fica mais claro do que uma sequência longa de testes manuais.
Usando uma função como filtro
O critério pode ser uma função que recebe a exceção e retorna verdadeiro ou falso. Essa opção é útil quando a decisão depende de atributos personalizados, códigos de resposta ou outras informações.
class ErroServico(Exception):
def __init__(self, codigo, mensagem):
super().__init__(mensagem)
self.codigo = codigo
def temporario(exc):
return isinstance(exc, ErroServico) and exc.codigo >= 500
retry, definitivos = grupo.split(temporario)
Com esse padrão, apenas as falhas temporárias podem ser enviadas para uma nova tentativa. Erros definitivos ficam separados para registro ou correção dos dados.
Exemplo em validação de registros
Considere uma função que recebe vários registros e deseja informar todos os problemas encontrados.
def validar_registros(registros):
erros = []
for indice, registro in enumerate(registros):
try:
if "email" not in registro:
raise KeyError(f"registro {indice}: email ausente")
if registro.get("idade", 0) < 0:
raise ValueError(f"registro {indice}: idade inválida")
except Exception as exc:
erros.append(exc)
if erros:
raise ExceptionGroup("erros de validação", erros)
Na camada que chama essa função, os campos ausentes podem ser separados dos valores inválidos. Isso permite mostrar mensagens diferentes ao usuário e registrar cada categoria de forma apropriada.
try:
validar_registros(registros)
except ExceptionGroup as grupo:
ausentes, restante = grupo.split(KeyError)
if ausentes:
registrar_campos_ausentes(ausentes)
if restante:
raise restante
O ponto mais importante é não ignorar o grupo restante. Se uma parte é tratada e a outra desaparece, falhas relevantes podem ficar sem registro.
Estruturas aninhadas
Grupos podem conter outros grupos. Isso acontece quando cada etapa de um pipeline ou cada tarefa produz seu próprio conjunto de erros. O método split() preserva essa árvore. Se uma falha veio da etapa de download, essa informação continua presente depois da divisão.
grupo = ExceptionGroup(
"pipeline",
[
ExceptionGroup("download", [TimeoutError("tempo esgotado")]),
ExceptionGroup("leitura", [ValueError("conteúdo inválido")]),
],
)
Ao separar TimeoutError, o resultado mantém o subgrupo chamado download. Isso facilita identificar a origem do problema.
split e subgroup
O método subgroup() retorna apenas a parte que corresponde ao filtro. Já split() retorna duas partes: correspondências e restante. Use subgroup() quando você só precisa consultar um subconjunto. Use split() quando precisa tratar uma categoria e depois continuar trabalhando com as outras exceções.
Boas práticas
Prefira filtrar por tipos ou atributos estáveis. Mensagens de erro podem mudar, ser traduzidas ou incluir detalhes variáveis. Evite depender apenas do texto. Também mantenha os grupos pequenos e relacionados ao mesmo contexto. Um grupo muito amplo, com erros de áreas diferentes, dificulta a leitura.
Registre o grupo completo antes de aplicar tratamentos destrutivos. Em sistemas importantes, inclua identificadores da tarefa, do arquivo ou do registro. Isso ajuda a reproduzir a falha. Nunca use split() apenas para descartar erros silenciosamente.
Testes
Os testes devem verificar os dois retornos, os tipos presentes e a preservação da estrutura.
def test_split_por_tipo():
grupo = ExceptionGroup(
"teste",
[ValueError("a"), TypeError("b")],
)
valores, outros = grupo.split(ValueError)
assert valores is not None
assert outros is not None
assert isinstance(valores.exceptions[0], ValueError)
assert isinstance(outros.exceptions[0], TypeError)
Também teste casos sem correspondência e casos em que todas as exceções correspondem. Isso confirma o comportamento de None nos retornos.
Quando usar
O método é adequado para processamento em lote, tarefas concorrentes, pipelines de dados, chamadas a vários serviços, validações de formulários, importações e testes compostos. Em funções simples que só produzem uma falha por vez, o tratamento tradicional costuma ser suficiente.
Conclusão
ExceptionGroup.split() ajuda a organizar múltiplas falhas sem perder contexto. Ele separa erros por tipo ou condição, preserva grupos aninhados e permite tratar apenas aquilo que a aplicação conhece. O restante pode continuar sendo propagado com segurança. Para complementar o estudo, veja os artigos da Academify sobre try e except, traceback, asyncio e erros comuns. Consulte ainda a documentação oficial e a PEP 654.







