O módulo configparser no Python lê e grava arquivos de configuração no estilo INI, organizados em seções, opções e valores textuais. Ele é adequado para aplicações desktop, ferramentas de linha de comando, scripts administrativos e programas que precisam permitir ajustes simples sem exigir JSON ou YAML.
O formato INI não possui uma especificação única e universal. Cada aplicação pode adotar regras diferentes para comentários, maiúsculas, delimitadores, valores vazios e interpolação. Por isso, configure o parser explicitamente e documente o dialeto aceito.
Crie um arquivo INI básico
[servidor]
host = 127.0.0.1
porta = 8080
debug = false
[logs]
nivel = INFO
arquivo = logs/app.logCada cabeçalho entre colchetes define uma seção. As opções usam = ou : como delimitador por padrão.
Leia a configuração
import configparser
config = configparser.ConfigParser()
lidos = config.read("app.ini", encoding="utf-8")
if not lidos:
raise FileNotFoundError("app.ini não foi carregado")
host = config["servidor"]["host"]
porta = config["servidor"].getint("porta")
debug = config["servidor"].getboolean("debug")read() ignora silenciosamente arquivos que não consegue abrir e devolve a lista dos que foram lidos. Se um arquivo é obrigatório, verifique o retorno ou use read_file() com um handle já aberto.
Todos os valores são strings
O parser não infere tipos automaticamente. Use getint(), getfloat() e getboolean().
timeout = config["servidor"].getfloat("timeout", fallback=5.0)
workers = config["servidor"].getint("workers", fallback=4)
ativo = config["servidor"].getboolean("ativo", fallback=True)getboolean() reconhece valores como yes/no, true/false, on/off e 1/0. Não use bool("false"), pois qualquer string não vazia é verdadeira.
Use fallbacks corretamente
No proxy de uma seção, o segundo argumento de get() é o fallback:
nivel = config["logs"].get("nivel", "INFO")Na API do parser, use a palavra-chave fallback:
nivel = config.get("logs", "nivel", fallback="INFO")Valores da seção DEFAULT têm prioridade sobre o fallback. Isso pode surpreender quando uma opção parece ausente na seção, mas é herdada.
Defina valores padrão
[DEFAULT]
timeout = 10
retries = 3
[api]
url = https://api.example.com
[worker]
retries = 5As opções de DEFAULT ficam visíveis em todas as seções. Remover uma sobrescrita faz o valor padrão reaparecer; ele não pertence fisicamente à seção.
Leia vários arquivos em camadas
Arquivos lidos depois sobrescrevem opções conflitantes, mas preservam as demais.
config.read(
["defaults.ini", "site.ini", "usuario.ini"],
encoding="utf-8",
)Uma arquitetura comum usa defaults versionados, configuração do servidor e overrides do usuário. Não use arquivos opcionais para parâmetros críticos sem validar que os valores essenciais estão presentes.
Use read_file para arquivos obrigatórios
from pathlib import Path
caminho = Path("defaults.ini")
with caminho.open(encoding="utf-8") as arquivo:
config.read_file(arquivo, source=str(caminho))Erros de sintaxe e abertura são propagados. O parâmetro source melhora a mensagem de diagnóstico.
Leia strings e dicionários
read_string() é útil em testes e conteúdo recebido de uma fonte controlada.
config.read_string("""
[servico]
url = https://example.com
""", source="configuração embutida")read_dict() carrega uma estrutura de mapeamentos e converte valores para texto.
config.read_dict({
"servidor": {"porta": 8080, "debug": False},
})Entenda maiúsculas e minúsculas
Por padrão, nomes de seções diferenciam maiúsculas, mas opções não. As chaves são normalizadas para minúsculas por optionxform().
config = configparser.ConfigParser()
config.read_string("""
[Secao]
MinhaChave = valor
""")
print(list(config["Secao"]))
# ['minhachave']Para preservar a caixa:
config.optionxform = strFaça isso antes de ler dados. A função de transformação deve ser idempotente.
Interpolação básica
O ConfigParser usa BasicInterpolation por padrão.
[caminhos]
base = /opt/minhaapp
logs = %(base)s/logs
cache = %(base)s/cachePara incluir um caractere percentual literal, escreva %%. A interpolação acontece quando o valor é obtido, não durante a leitura.
Interpolação estendida
ExtendedInterpolation usa a sintaxe ${seção:opção} e permite referências entre seções.
from configparser import ConfigParser, ExtendedInterpolation
config = ConfigParser(interpolation=ExtendedInterpolation())[comum]
raiz = /srv/app
[logs]
dir = ${comum:raiz}/logs
Use $$ para um cifrão literal. Ciclos e referências ausentes geram exceções de interpolação.
Desative a interpolação quando necessário
Valores como padrões, templates e senhas podem conter % ou $. Se a interpolação não faz parte do formato:
config = configparser.ConfigParser(interpolation=None)Também é possível usar get(..., raw=True) para uma leitura específica.
Conversores personalizados
O parâmetro converters cria novos métodos get*.
from pathlib import Path
config = configparser.ConfigParser(
converters={"path": Path, "lista": lambda v: [x.strip() for x in v.split(",")]},
)
pasta = config["logs"].getpath("arquivo")
origens = config["cors"].getlista("origens")Conversão não é validação completa. Verifique faixas, extensões, existência, permissões e regras de negócio após converter.
Personalize valores booleanos
config.BOOLEAN_STATES = {
"habilitado": True,
"desabilitado": False,
}Um vocabulário customizado pode facilitar arquivos localizados, mas reduz portabilidade. Documente os valores aceitos.
Arquivos com opções sem valor
Alguns formatos usam flags sem delimitador.
config = configparser.ConfigParser(allow_no_value=True)[recursos]
modo_seguro
auditoria
Essas opções retornam None. No Python recente, continuar uma opção sem valor com linha indentada gera MultilineContinuationError.
Seções sem nome
Python 3.13 adicionou suporte opcional a uma seção inicial sem cabeçalho.
config = configparser.ConfigParser(allow_unnamed_section=True)
config.read_string("""
chave = valor
[outra]
x = 1
""")
valor = config[configparser.UNNAMED_SECTION]["chave"]Ative o recurso apenas quando precisar compatibilidade com um formato existente.
Comentários e valores multilinha
Por padrão, # e ; iniciam comentários em linhas próprias. Comentários inline ficam desativados porque não existe escape confiável para os prefixos.
Valores multilinha precisam ser indentados além da chave:
[mensagem]
texto = primeira linha
segunda linha
terceira linhaQuando arquivos são editados por pessoas, considere empty_lines_in_values=False para reduzir ambiguidades visuais.
Modo estrito
strict=True, padrão atual, rejeita seções e opções duplicadas dentro da mesma fonte.
Essa validação captura erros de digitação e colisões causadas pela normalização de caixa. Mantenha-a ativa em novos projetos.
Trate exceções de forma clara
try:
with open("app.ini", encoding="utf-8") as arquivo:
config.read_file(arquivo)
except configparser.MissingSectionHeaderError as erro:
raise RuntimeError("Arquivo sem cabeçalho de seção") from erro
except configparser.DuplicateOptionError as erro:
raise RuntimeError("Opção duplicada") from erro
except configparser.InterpolationError as erro:
raise RuntimeError("Interpolação inválida") from erroInclua fonte e linha no diagnóstico, mas não registre valores secretos.
Grave a configuração
from pathlib import Path
config["servidor"]["porta"] = "9090"
with Path("app.ini").open("w", encoding="utf-8") as arquivo:
config.write(arquivo)Todos os valores devem ser strings. No Python 3.14, write() gera InvalidWriteError se a representação não puder ser lida corretamente depois.
Escreva de forma atômica
Não sobrescreva diretamente um arquivo importante. Grave em um arquivo temporário no mesmo diretório, faça flush(), sincronize e substitua com os.replace().
import os
from pathlib import Path
from tempfile import NamedTemporaryFile
destino = Path("app.ini")
with NamedTemporaryFile("w", encoding="utf-8", dir=destino.parent, delete=False) as temp:
config.write(temp)
temp.flush()
os.fsync(temp.fileno())
temporario = temp.name
os.replace(temporario, destino)Controle permissões e proprietário. Em escrita concorrente, use locking ou um serviço central de configuração.
Comentários não são preservados
Ao ler e escrever novamente, comentários e formatação original são perdidos. Se usuários mantêm documentação importante no arquivo, evite reescrevê-lo automaticamente ou use uma biblioteca que preserve o layout.
Não guarde segredos no INI
Arquivos INI são texto simples. Senhas, tokens e chaves devem vir de um gerenciador de segredos, variável de ambiente protegida ou credencial do sistema. Se um segredo precisar ser referenciado, armazene apenas seu identificador.
O guia de site no Python explica caminhos de instalação e ambientes; importlib.resources ajuda a distribuir defaults dentro de pacotes; e fileinput no Python trata processamento de vários arquivos.
Valide depois de ler
def carregar_servidor(config):
porta = config["servidor"].getint("porta")
if not 1 <= porta <= 65535:
raise ValueError("porta fora da faixa")
host = config["servidor"].get("host", "127.0.0.1").strip()
if not host:
raise ValueError("host vazio")
return host, portaO parser garante estrutura e conversões básicas; seu aplicativo deve validar semântica.
ConfigParser versus TOML e JSON
INI é simples e amigável para configurações pequenas. TOML possui especificação mais rigorosa e tipos nativos; JSON é interoperável, mas não aceita comentários. Escolha o formato pela complexidade, ecossistema e necessidade de edição humana.
Boas práticas
- Use UTF-8 explicitamente.
- Mantenha
strict=True. - Verifique arquivos obrigatórios.
- Defina o comportamento de caixa.
- Desative interpolação se não for necessária.
- Valide valores após converter.
- Escreva atomicamente.
- Não armazene segredos.
Conclusão
O configparser no Python oferece uma interface madura para configurações INI, com seções, defaults, camadas, interpolação e conversores. Ele funciona bem quando o formato permanece simples e claramente documentado.
Consulte a documentação oficial do configparser e a documentação do tomllib.







