Pular para o conteúdo principal

As falhas da leitura

Abrir e ler o arquivo de configuração (página anterior) pode dar errado: o arquivo pode não existir, ser uma pasta, estar sem permissão de leitura ou não estar em UTF-8. O enunciado cita "arquivo não encontrado" entre os erros que precisam virar uma mensagem clara. Esta página transforma cada uma dessas falhas numa linha que o usuário entende.

As falhas do sistema viram ConfigError​

O open e o readlines levantam exceções do próprio Python quando algo dá errado. O load as captura e levanta um ConfigError, a exceção de configuração da parte 10:

try:
# utf-8-sig drops a leading BOM; text mode turns \r\n and \r
# into line ends.
with open(path, encoding="utf-8-sig") as file:
lines = file.readlines()
except FileNotFoundError:
raise ConfigError(
f"configuration file not found: {path}") from None
except UnicodeDecodeError:
raise ConfigError(
f"configuration file is not valid UTF-8: {path}") from None
except OSError as error:
raise ConfigError(f"cannot read configuration file {path}: "
f"{error.strerror}") from None
ExceçãoQuandoMensagem
FileNotFoundErroro arquivo não existeconfiguration file not found: nao_existe.txt
UnicodeDecodeErroros bytes não formam UTF-8 (um arquivo salvo em Latin-1, por exemplo)configuration file is not valid UTF-8: latin1_config.txt
OSErrorqualquer outra falha do sistema: é uma pasta, falta permissão...cannot read configuration file pasta_config: Is a directory

O from None no fim de cada raise descarta a exceção original, que a nova mensagem já resume (página 2).

Por que converter​

O main, a função principal do a_maze_ing.py (parte 14), captura ConfigError e imprime Error: <mensagem> numa linha. Ele também tem um except genérico, o último, que existe para bugs e imprime Error: unexpected: .... Um OSError que escapasse daqui cairia nesse except genérico, como se fosse um defeito do programa. Converter aqui, onde o arquivo é aberto, garante que todo problema causado pelo usuário saia como uma linha clara.

O path vai na mensagem exatamente como o usuário digitou (config.txt, ../outro.cfg), para ele reconhecer de que arquivo se fala.

O try em volta do with inteiro​

O UnicodeDecodeError não acontece no open, e sim no readlines(), quando o Python tenta transformar os bytes em texto. Por isso o try cobre a leitura também, e não só a abertura.

A ordem dos except​

O Python testa os except de cima para baixo e usa o primeiro que combina. FileNotFoundError é uma subclasse ("filha") de OSError (todo arquivo não encontrado é uma falha do sistema). Se o except OSError viesse antes, ele capturaria o arquivo inexistente, e a mensagem específica nunca apareceria. Por isso a ordem vai do mais específico para o mais geral.

UnicodeDecodeError não é filha de OSError (é um tipo de ValueError), então a posição dela não muda o resultado; fica antes do OSError só para manter a leitura do específico para o geral.

strerror em vez de str(error)​

str(error) → [Errno 21] Is a directory: 'pasta_config'
error.strerror → Is a directory

str(error) traz o número interno do erro e repete o caminho, que a mensagem já cita. strerror é só a frase do sistema operacional.

O resto do load, que separa as linhas em chave e valor, está na próxima página, e o Experimente da página 10 provoca cada uma destas mensagens.