datatool
Diagnostica, perfila, limpa e converte arquivos de dados pela linha de comando: CSV, Excel, JSON, Parquet e outros. Aponta valores nulos, duplicidades, datas em formatos diferentes, números guardados como texto e CPF/CNPJ inválido, e sugere o comando que corrige cada problema. Entende nativamente CSV exportado pelo Excel em português (;, cp1252), CPF/CNPJ e valores em R$.
pip install datatool-cli
datatool info clientes.csv
O roadmap completo, com o status de cada funcionalidade, está em specs/README.md.
Status
- Implementado:
convert,info,profile(+--columns/--max-columns),clean(diagnóstico +--trim/--lowercase/--uppercase/--normalize-case/--remove-duplicates/--fill-null/--drop-null/--normalize-dates/--fix-types/--rename-columns/--remove-columns/--normalize-documents), saída em JSON (--format json) eminfo/profile/clean/convert,--redact-valueseminfo/profile/clean, detecção de delimitador/encoding de CSV (--sep/--encoding), log de execução (no diretório de logs do usuário, configurável), validação de CPF/CNPJ, servidor MCP (datatool-mcp) para agentes de IA - Ainda não implementado: relatório HTML de profiling, pipelines YAML, inspeção e limpeza de planilhas Excel, IA opcional, licenciamento Pro — veja specs/README.md para o detalhamento spec a spec
Requisitos
- Python >= 3.10
Instalação
pip install datatool-cli
O pacote se chama datatool-cli, mas o comando é datatool. datatool --version mostra a versão instalada, e datatool --help lista os comandos.
Para o servidor MCP, usado por agentes de IA (ver a seção própria), que traz dependências a mais:
pip install "datatool-cli[mcp]"
Para instalar a partir do código-fonte, veja Desenvolvimento.
Comandos disponíveis
convert — converter arquivo entre formatos
datatool convert vendas.csv vendas.parquet
datatool convert vendas.xlsx vendas.csv
- Formatos suportados: CSV, JSON, JSONL, Excel (xlsx), Parquet, SQLite, além de Feather e Avro.
- SQLite: na leitura,
--tableescolhe a tabela. Sem ele, é lida a tabela com o nome do arquivo (vendas.db→ tabelavendas) ou, se o banco tem uma só, essa; com várias tabelas e nenhuma com esse nome, o comando lista as tabelas e pede--table(exit code 2). O JSON traztableetablesno resumo do arquivo. Na gravação, a tabela tem o nome do arquivo. Com--overwritenum.dbque já existe, a tabela é substituída numa única transação: se a gravação falhar, a tabela original fica intacta. As demais tabelas do arquivo não são tocadas. Booleanos, datas e data-hora são gravados com o tipo declarado (BOOLEAN,DATE,TIMESTAMP) e voltam com o mesmo tipo na leitura. Data-hora com fuso volta em UTC, no mesmo instante. - Colunas só de inteiros com valores que não cabem em 64 bits, como a chave de acesso da NF-e (44 dígitos) ou o código de barras de um boleto, são lidas como texto: são identificadores, e como texto não perdem nenhum dígito.
- Os tipos das colunas são inferidos com o arquivo inteiro, não só com as primeiras linhas: um valor como
N/Dnuma coluna numérica, em qualquer posição, faz a coluna ser lida como texto, sem perder nenhum valor, em vez de impedir a leitura ou virar nulo. Oinfoaponta a coluna. - O formato de entrada e saída é inferido pela extensão do arquivo. Use
--from-type/--to-typepara sobrescrever quando a extensão não é reconhecida ou é ambígua. - Com
to_filename, uma linha de confirmação vai para o stderr:Gravado vendas.parquet (parquet): 1.500 linhas, 8 colunas. - Se
to_filenamefor omitido, o dataset inteiro é impresso no stdout em CSV, pronto para pipe (datatool convert vendas.xlsx | head). - Se o destino já existir, o comando recusa (exit code 2) e não altera nada; use
--overwritepara substituí-lo. --show-statsimprime (linhas, colunas) da origem e do destino; semto_filename, vai para o stderr, para não se misturar ao CSV.--format jsonimprime um documento comsourceetarget(exigeto_filename; não combina com--show-stats).
datatool convert vendas.csv vendas.parquet --show-stats
Arquivos inexistentes, formatos não suportados ou diretórios sem permissão de escrita retornam uma mensagem clara e exit code diferente de zero.
info — diagnóstico automático de um arquivo
datatool info clientes.csv
Mostra linhas, colunas e tamanho do arquivo, além de detectar automaticamente:
- valores nulos por coluna
- linhas duplicadas
- colunas com múltiplos formatos de data
- colunas numéricas armazenadas como texto
- colunas quase numéricas com alguns valores que não são números (
N/D,a combinar), sem sugestão: o--fix-typesnão as converte, para não apagar esses valores. Se eles querem dizer "sem dado",clean --null-values "N/D" --fix-typesos troca por nulo e converte a coluna
Para cada problema que tem correção, sugere o comando datatool clean correspondente. Todas as sugestões (--fix-types, --remove-duplicates, --normalize-dates, --drop-null) já estão implementadas. Funciona para CSV, JSON, Excel e Parquet.
Arquivo: clientes.csv
Linhas: 10
Colunas: 6
Tamanho: 711 bytes
Problemas encontrados:
⚠ 3 valores nulos em "email"
⚠ 1 linhas duplicadas
⚠ "data_nascimento" contém 4 formatos de data diferentes
⚠ 10 CPFs com dígito verificador inválido
⚠ "idade" parece numérica, mas 1 valores não são números
Sugestões:
1. Remover duplicidades → datatool clean clientes.csv --remove-duplicates
2. Normalizar datas → datatool clean clientes.csv --normalize-dates
3. Tratar valores nulos → datatool clean clientes.csv --drop-null
Um arquivo de exemplo que dispara todos esses problemas está em examples/clientes.csv.
profile — profiling estatístico de um dataset
datatool profile vendas.csv
datatool profile vendas.csv --key cpf
Para cada coluna, mostra contagem e percentual de nulos, e:
- colunas numéricas: min, max, média, mediana, desvio padrão, percentis (25/50/75) e outliers (método IQR)
- colunas categóricas/texto: cardinalidade e top 5 valores mais frequentes (com percentual)
Também reporta a quantidade de linhas totalmente duplicadas e, com --key coluna1,coluna2, a quantidade de duplicidades considerando apenas essas colunas como chave.
Arquivo: clientes.csv
Linhas: 10
Colunas: 6
Linhas duplicadas: 1
Linhas duplicadas (chave: cpf): 1
Coluna "cpf" (numérica)
Nulos: 0 (0.00%)
Min: 11122233344.00 Max: 99900011122.00 Média: 52222222221.70 Mediana: 50011122232.50 Desvio padrão: 30544672345.70
Percentis: p25=25011122232.75 p50=50011122232.50 p75=75011122149.75
Outliers (IQR): 0
Coluna "cidade" (categórica)
Nulos: 0 (0.00%)
Cardinalidade: 9
Top 5 valores:
Rio de Janeiro: 2 (20.00%)
São Paulo: 1 (10.00%)
...
Em datasets largos, --columns e --max-columns restringem o tamanho da saída:
datatool profile vendas.csv --columns preco,quantidade
datatool profile vendas.csv --max-columns 50
--columns col1,col2perfila só essas colunas (a contagem de linhas duplicadas continua do dataset inteiro); coluna inexistente é erro claro, igual a--key--max-columns Nperfila só as N primeiras colunas na ordem do dataset (mesmo que--columnspeça outra ordem); o que ficou de fora aparece no fim do texto, ou emcolumns_returned/columns_total/truncated_columnsno JSON- Sem
--max-columns, nada muda — a flag é só um limite opcional
clean — detectar e corrigir problemas de qualidade
datatool clean clientes.csv
Sem nenhuma flag, é somente leitura/diagnóstico — não grava nenhum arquivo. Detecta, por coluna:
- valores inválidos (ex.: e-mail fora do formato)
- variação de formato (ex.: telefone em formatos diferentes)
- espaços extras nas bordas dos valores
- duplicidade por chave (coluna majoritariamente única com alguns valores repetidos, ex.: CPF)
- inconsistência de capitalização (ex.: "Porto Alegre" / "PORTO ALEGRE" / "porto alegre")
- nome de coluna com espaços nas pontas (ex.:
" email ", comum em exportações do Excel), com o--rename-columnsque os tira
Arquivo: clientes_sujos.csv
Linhas: 20
Colunas: 5
nome
1 registros com espaços extras
email
1 valores inválidos
telefone
3 formatos diferentes
cpf
1 valores duplicados
cidade
"PORTO ALEGRE"
"Porto Alegre"
"porto alegre"
Um arquivo de exemplo que dispara todos esses problemas está em examples/clientes_sujos.csv.
Com pelo menos uma flag de operação, o comando passa a transformar os dados (só em colunas de texto — colunas numéricas, por exemplo, não são alteradas) e mostra o resultado: grava em --output arquivo (formato inferido pela extensão, igual ao convert) ou, se omitido, imprime o dataset inteiro em CSV no stdout, com o relatório das operações no stderr. Nada é gravado por padrão, e um --output que já existe só é substituído com --overwrite. Ao gravar, uma linha de confirmação vai para o stderr, depois do relatório: Gravado clientes_limpo.csv (csv): 20 linhas, 5 colunas.
Opções que só configuram uma operação exigem essa operação: --key precisa de --remove-duplicates, --drop-null-columns de --drop-null, --document-columns de --normalize-documents, --date-columns de --normalize-dates e --decimal-separator de --fix-types. Sem ela, o comando falha (exit code 2) em vez de ignorar a opção. Pelo mesmo motivo, --output/--overwrite sem nenhuma operação é erro: sem operação, o clean só faz o diagnóstico e não grava nada.
datatool clean clientes.csv --trim --normalize-case --output clientes_limpo.csv
datatool clean clientes.csv --lowercase --output clientes_limpo.csv
datatool clean clientes.csv --uppercase --output clientes_limpo.csv
--trimremove espaços extras nas bordas--lowercase/--uppercaseconvertem a caixa de todo o texto da coluna--normalize-caseunifica variações de capitalização em title case ("PORTO ALEGRE"/"porto alegre"→"Porto Alegre")--trimcombina com qualquer uma das outras e roda primeiro;--lowercase,--uppercasee--normalize-casesão mutuamente exclusivas (passar duas é erro, exit code 2)
nome,email,telefone,cpf,cidade
Pessoa 1,Pessoa1@Example.Com,(11) 91234-5678,10000000001,Porto Alegre
Pessoa 2,Pessoa2@Example.Com,11 91234-5678,10000000002,Porto Alegre
Pessoa 3,Invalido-Sem-Arroba,11912345678,10000000003,Porto Alegre
--remove-duplicates remove linhas duplicadas, mantendo a primeira ocorrência, e reporta quantas foram removidas:
datatool clean clientes.csv --remove-duplicates
datatool clean clientes.csv --remove-duplicates --key cpf --output clientes_limpo.csv
- Por padrão considera a linha inteira (todas as colunas iguais);
--key coluna1,coluna2deduplica por um subconjunto de colunas - A quantidade de linhas removidas é sempre impressa, mesmo gravando em arquivo via
--output - Combinável com as flags de texto acima — quando combinadas,
--trim/--lowercase/--uppercase/--normalize-caserodam antes da remoção de duplicidades, então linhas que só diferiam por espaço ou capitalização também são deduplicadas
--fill-null/--drop-null tratam valores nulos e reportam quantas células/linhas foram afetadas:
datatool clean clientes.csv --null-values "N/D,-"
datatool clean clientes.csv --fill-null "N/A"
datatool clean clientes.csv --fill-null "idade:0" --output clientes_limpo.csv
datatool clean clientes.csv --drop-null
datatool clean clientes.csv --drop-null --drop-null-columns email --output clientes_limpo.csv
--fill-null valor(sem:) preenche nulos só nas colunas de texto — evita converter uma coluna numérica inteira para texto ao preencher com um valor não numérico--fill-null coluna:valorpreenche só essa coluna, convertendo o valor para o tipo da coluna quando ela é numérica; um valor incompatível com o tipo (ex.:idade:abc) é erro, exit code 2, em vez de transformar a coluna em texto; é repetível (--fill-null "N/A" --fill-null "idade:0")--null-values "N/D,-"troca por nulo, nas colunas de texto, os valores que querem dizer "sem dado". A comparação ignora os espaços nas pontas e diferencia maiúsculas de minúsculas. Roda antes das demais operações, então--null-values "N/D" --fix-typesconverte uma coluna de números comN/D, e--fill-null/--drop-nulltratam os nulos que ela criou--drop-nullremove linhas com nulos em qualquer coluna por padrão, ou só nas colunas de--drop-null-columns coluna1,coluna2(--columnscontinua aceito como nome antigo)
--normalize-dates converte datas em formatos variados para ISO 8601 (yyyy-mm-dd):
datatool clean clientes.csv --normalize-dates
datatool clean clientes.csv --normalize-dates --date-columns data_nascimento,data_cadastro --output clientes_limpo.csv
- Sem
--date-columns, detecta automaticamente as colunas de texto em que a maioria dos valores (≥ 60% de uma amostra) parece data - Formatos reconhecidos:
yyyy-mm-dd,yyyy/mm/dd,yyyy.mm.dd,yyyy-mm-ddThh:mm:ss(a hora é descartada),dd/mm/yyyy,dd-mm-yyyy,dd.mm.yyyy,dd/mm/yy,dd-mm-yye as variantesmm/dd - Datas ambíguas como
01/02/1990são lidas comodd/mm; a coluna só é tratada comomm/ddquando tem valores que só fazem sentido assim (ex.:12/31/1990) e nenhum que só faça sentido comodd/mm - Anos com 2 dígitos seguem a regra do Python:
00–68→ 2000–2068,69–99→ 1969–1999 - Valores não reconhecidos são mantidos como estão e listados na saída:
"data_nascimento": 6 datas normalizadas
"data_nascimento": 1 valores não reconhecidos como data, mantidos sem alteração:
"20261301"
--fix-types converte para número as colunas numéricas armazenadas como texto, inclusive valores monetários em formato brasileiro:
datatool clean relatorio.csv --fix-types --output relatorio_limpo.parquet
datatool clean relatorio.csv --fix-types --decimal-separator , --output relatorio_limpo.parquet
- Detecta automaticamente as colunas de texto em que ≥ 90% de uma amostra dos valores é numérica
- Remove
R$e espaços antes de converter --decimal-separator ,ou--decimal-separator .define o separador decimal de todas as colunas; o de milhar é o outro caractere. Com,:1.234,56→1234.56e1.500→1500. Com.:1,234.56→1234.56e1.500→1.5- Sem
--decimal-separator, num CSV separado por;(o do Excel em português) a vírgula é o decimal e o ponto, o milhar:1.500→1500. Nos demais arquivos, decide por coluna: se algum valor tem vírgula ouR$, usa,como decimal; senão,., e uma coluna só com valores como1.500é lida como1.5(informe--decimal-separator ,para ler como1500) - A coluna vira
intquando nenhum valor tem parte decimal, senãofloat - Colunas com zeros à esquerda (
01001000, típico de CEP/CPF) são ignoradas, porque a conversão perderia os zeros - Uma coluna com algum valor que não é número (
N/D,a combinar, um código comoA12) não é convertida: continua como texto, sem perder nenhum valor, e os valores aparecem na saída. As demais colunas são convertidas normalmente:
"valor": não convertida, 1 valores não são números (a coluna continua como texto):
"a combinar"
"idade": não convertida, 1 valores não são números (a coluna continua como texto):
"N/D"
"preco": convertida para float
Se esses valores querem dizer "sem dado", --null-values os troca por nulo antes da conversão (ex.: --null-values "N/D,-" --fix-types).
--rename-columns/--remove-columns ajustam o schema:
datatool clean vendas.csv --rename-columns old_name:new_name,foo:bar --output vendas_limpo.csv
datatool clean vendas.csv --remove-columns coluna_interna,coluna_temp --output vendas_limpo.csv
- Coluna inexistente, entrada sem
:em--rename-columnsou renomeação que geraria nomes repetidos são erro claro, sem gravar nada - Nomes de coluna com espaços nas pontas (
" email ") podem ser referenciados sem os espaços, aqui e em--key,--columns,--drop-null-columns,--date-columns,--document-columnse--fill-null coluna:valor;--rename-columns email:emailtira os espaços. Se duas colunas tiverem o mesmo nome sem os espaços ("email"e" email "), é erro (exit code 2) - São aplicadas antes das demais operações (primeiro remove, depois renomeia):
--key,--drop-null-columns,--date-columnse--fill-null coluna:valorusam os nomes já renomeados, e colunas removidas não entram na deduplicação
--normalize-documents valida e padroniza CPF/CNPJ, inclusive o CNPJ alfanumérico (letras nas 12 primeiras posições, emitido pela Receita desde julho de 2026):
datatool clean clientes.csv # diagnóstico passa a incluir CPF/CNPJ
datatool clean clientes.csv --normalize-documents digits # 123.456.789-09 → 12345678909
datatool clean clientes.csv --normalize-documents masked # 12345678909 → 123.456.789-09
datatool clean clientes.csv --normalize-documents masked --document-columns cpf,cnpj_empresa
- Detecta colunas de texto ou numéricas que "parecem" CPF/CNPJ (formato batendo numa amostra e dígito verificador majoritariamente válido, máscara presente, ou
cpf/cnpj/documentono nome da coluna) — sem--document-columns, aplica a todas elas - Diagnóstico (
cleansem flags einfo) reporta, por coluna: dígito verificador inválido, todos os dígitos iguais (ex.:111.111.111-11), valores fora do formato, mistura de máscara/sem máscara e, em coluna numérica, zeros à esquerda perdidos na leitura digitsremove a máscara;maskedaplicaXXX.XXX.XXX-XX(CPF) ouXX.XXX.XXX/XXXX-XX(CNPJ), com letras sempre maiúsculas- Coluna numérica (CPF lido como
Int64perde zeros à esquerda) é completada com0e sempre vira texto - Normalizar não valida: documentos com dígito inválido são formatados do mesmo jeito, e o comando informa quantos continuam inválidos; só valores fora do formato (nem CPF nem CNPJ) ficam como estão
- Nunca mostra o CPF/CNPJ no terminal fora do próprio dataset — o diagnóstico e o log só trazem contagens
"cpf": 1.180 documentos normalizados
"cpf": 23 com dígito verificador inválido (formatados, mas continuam inválidos)
"cpf": 2 valores fora do formato de CPF/CNPJ, mantidos sem alteração
CSV com ; ou em cp1252 (Excel em português)
convert, info, profile e clean detectam sozinhos o delimitador (,, ;, tab ou |) e o encoding (UTF-8, com ou sem BOM, UTF-16 com BOM, como o "Texto Unicode" do Excel, ou cp1252) do CSV de entrada. Um CSV exportado pelo Excel em português funciona sem nenhuma opção. Para forçar:
datatool info vendas.csv --sep ";" --encoding latin-1
datatool convert vendas.csv vendas.parquet --sep "\t"
--sepaceita um caractere (ou\tpara tab);--encodingaceita qualquer codec do Python (cp1252,latin-1,utf-16, ...)- Valem só para o arquivo de entrada e só para CSV; a saída CSV continua com
,e UTF-8 - Num CSV separado por
;, a vírgula é o separador decimal já na leitura:10,5é lido como o número 10,5. Valores com ponto de milhar (1.500,1.234,56) chegam como texto, e oinfoaponta a coluna;datatool clean ... --fix-typesos converte lendo o ponto como milhar (1.500→1500). Num CSV separado por vírgula, vale o padrão americano (1.500é 1,5)
Planilhas Excel com várias abas (--sheet)
datatool info relatorio.xlsx --sheet "Vendas 2025"
datatool convert relatorio.xlsx clientes.csv --sheet 3
- Sem
--sheet,convert,info,profileecleanleem a primeira aba visível com dados: abas vazias (uma capa, por exemplo) e ocultas são puladas - Quando a planilha tem outras abas, um aviso no stderr diz qual foi lida:
Aviso: relatorio.xlsx tem 3 abas (Resumo, Vendas 2025, Clientes); lida: "Resumo". Use --sheet para escolher outra. --sheetaceita o nome da aba ou a posição a partir de 1, como no Excel; o nome tem prioridade, então uma aba chamada2025é encontrada pelo nome. Abas ocultas só são lidas quando pedidas com--sheet- O texto mostra
Aba: Vendas 2025 (2 de 3)logo depois de "Arquivo:", e o JSON trazsheetesheetsno resumo do arquivo - As sugestões do
infoincluem a aba, para o comando sugerido corrigir a aba certa (datatool clean relatorio.xlsx --sheet 'Vendas 2025' --fix-types) - Aba inexistente é erro (exit code 2) com a lista de abas; aba vazia pedida com
--sheet, ou planilha sem nenhuma aba com dados, é erro com exit code 1 - Ao gravar em
.xlsx, o resultado tem uma aba só, com o nome da aba lida. Por isso, gravar sobre a própria planilha de entrada quando ela tem mais de uma aba é recusado (exit code 2), mesmo com--overwrite, já que apagaria as outras abas: grave em outro arquivo
Log de execução
Toda execução registra em datatool.log, no diretório de logs do usuário (~/Library/Logs/datatool no macOS, ~/.local/state/datatool/log no Linux, %LOCALAPPDATA%\datatool\Logs no Windows), o que foi feito: comando e opções, delimitador/encoding usados, arquivos lidos e gravados, operações do clean com as contagens, erros, exit code e duração. O terminal não muda.
2026-09-25 15:40:46,811 INFO [41227a] clean: início — args: filename=vendas.csv, fix_types=True, decimal_separator=,, output=limpo.csv, output_format=text
2026-09-25 15:40:46,811 INFO [41227a] clean: encoding detectado: cp1252 (arquivo não é UTF-8 válido)
2026-09-25 15:40:46,812 INFO [41227a] clean: delimitador detectado: ';'
2026-09-25 15:40:46,814 INFO [41227a] clean: --fix-types: "valor" convertida para float
2026-09-25 15:40:46,815 INFO [41227a] clean: gravado limpo.csv (csv) — 2 linhas, 2 colunas
2026-09-25 15:40:46,815 INFO [41227a] clean: fim — exit code 0, 0,00 s
- O log nunca contém valores das células (só caminhos, nomes de coluna, contagens e opções)
- Rotação a cada 5 MB, mantendo até 3 arquivos antigos (
datatool.log.1a.3) - Se o log não puder ser gravado (ex.: diretório somente leitura), o comando roda normalmente, sem log
DATATOOL_LOG_DIR=caminhograva em outro diretório (relativo ao diretório atual, se não for absoluto; ex.:DATATOOL_LOG_DIR=logsvolta ao comportamento antigo, em./logs)DATATOOL_NO_LOG=1desliga o log
Saída em JSON (--format json)
info, profile, clean e convert aceitam --format json (o padrão é --format text, a saída descrita acima). O stdout passa a ser um único documento JSON, para uso em scripts, notebooks e CI:
datatool info clientes.csv --format json | jq '.problems[] | select(.category == "nulls")'
datatool profile clientes.csv --format json > perfil.json
datatool clean clientes.csv --fix-types --remove-duplicates --output limpo.parquet --format json
{
"schema_version": 1,
"command": "info",
"status": "ok",
"file": {"path": "examples/clientes.csv", "format": "csv", "rows": 10, "columns": 6, "size_bytes": 711},
"problems": [
{"category": "nulls", "column": "email", "count": 3, "message": "3 valores nulos em \"email\""}
],
"suggestions": [
{"category": "nulls", "label": "Tratar valores nulos", "command": "datatool clean examples/clientes.csv --drop-null"}
]
}
- Em planilhas Excel, o resumo do arquivo (
file, ousourcenoconvert) trazsheet(a aba lida) esheets(todas as abas, com"hidden": truenas ocultas); em bancos SQLite,table(a tabela lida) etables(todas) - Cada problema traz
countecount_unit(rows,values,formats,variantsoucolumns), que diz o que está sendo contado - Todo documento traz
schema_version,commandestatus;infotrazproblems/suggestions,profiletrazduplicates/columns, ocleantrazproblems(diagnóstico) ouoperations/output(com operações), e oconverttrazsource/target - Números sem formatação pt-BR nem arredondamento;
NaNviranull - Erros também saem em JSON (
"status": "error"), com o mesmo exit code do modo texto - No
cleancom operações,--outputé obrigatório, e noconvert, oto_filename: o JSON é só o relatório, os dados vão para o arquivo - O formato completo, campo a campo, está em specs/019-saida-json.md
Ocultar valores de célula (--redact-values)
info, profile e clean aceitam --redact-values (padrão desligado), nos dois formatos, para tirar valores de célula do relatório sem perder as contagens — útil ao colar a saída num chat de IA, ticket de suporte ou log de CI:
datatool profile clientes.csv --redact-values
datatool clean clientes.csv --redact-values
- Em
profile, os valores mais frequentes viram<valor 1>,<valor 2>, ...;count/percentcontinuam reais - No diagnóstico, a inconsistência de capitalização passa a mostrar só a contagem (
"3 variações de capitalização"), em vez de listar as variantes - Nas operações do
clean(--normalize-dates,--fix-types,--normalize-documents), os valores não reconhecidos somem da lista — fica só a contagem e(valores ocultos por --redact-values) - Nunca muda o arquivo gravado por
--output, só o que é impresso ou volta em--format json
Servidor MCP (datatool-mcp)
Expõe info, profile, clean (diagnóstico e operação) e convert como ferramentas MCP para um agente de IA (Claude Code, Claude Desktop, Cursor, ...) chamar diretamente, em vez de escrever código de análise do zero a cada conversa. Requer pip install "datatool-cli[mcp]" (ver Instalação) — quem só usa o CLI não precisa dessa dependência.
{
"mcpServers": {
"datatool": {
"command": "datatool-mcp",
"args": ["--root", "/caminho/do/projeto"]
}
}
}
- Ferramentas:
datatool_info,datatool_profile(+columns/max_columns, padrão 50),datatool_clean_diagnose,datatool_clean_apply(grava emoutput) edatatool_convert(grava emto_filename) — cada uma devolve o mesmo JSON de--format json - Todo caminho de arquivo fica restrito ao diretório passado em
--root;output/to_filenamenunca pode ser o mesmo arquivo da entrada, e uma saída já existente exigeoverwrite: true redact_valuesvem ligado por padrão nas ferramentas (diferente do CLI, onde vem desligado): os valores de célula não trafegam para o modelo de IA a menos que a pessoa configure a ferramenta comredact_values: false- Em planilhas Excel, todas as ferramentas aceitam
sheet(nome ou posição), e o JSON devolvido lista as abas emfile.sheets(source.sheetsnoconvert), para o agente escolher a aba certa; em bancos SQLite,table, com a lista emfile.tables - No
datatool_clean_apply,drop_null_columnsrestringe odrop_nulla essas colunas;columns, o nome antigo, ainda é aceito, mas será removido numa versão futura - Cada chamada é registrada em
<root>/logs/datatool.log(ou ondeDATATOOL_LOG_DIRapontar), com o nome prefixado (mcp info,mcp clean, ...) - Só ferramentas Community por enquanto — o detalhamento completo está em specs/020-mcp-server.md
Desenvolvimento
Instalar a partir do código-fonte, em modo editável (alterações em src/datatool/ valem sem reinstalar), com as ferramentas de teste, lint e checagem de tipos, que já incluem o servidor MCP:
git clone https://github.com/wvcode/cli-python.git
cd cli-python
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
Para apenas rodar via módulo, sem instalar: PYTHONPATH=src python -m datatool.main <comando> ...
Rodar os testes (com cobertura; o CI exige pelo menos 95%):
pytest --cov
Rodar o lint, o formatador e a checagem de tipos:
ruff check src/ tests/
ruff format --check src/ tests/
pyright
- Os testes ficam em
tests/, um arquivo por comando/assunto;conftest.pyehelpers.pytêm o que é compartilhado - Durante os testes, o log vai para
./logsdo diretório temporário de cada teste (DATATOOL_LOG_DIR, noconftest.py) - As versões mínimas declaradas em
pyproject.tomlsão verificadas no CI (jobtest-minimum, comuv pip install --resolution lowest-direct) - A versão vem da tag do git (
setuptools-scm): publicar uma release com a tagv0.2.0gera o pacote0.2.0
Estrutura do projeto
src/datatool/ código-fonte do CLI (comandos, leitura/gravação, heurísticas)
tests/ suíte de testes (pytest)
specs/ uma spec por user story, com critérios de aceite e status
examples/ arquivos de exemplo para testar os comandos manualmente
Metadata
Release files for datatool-cli 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| datatool_cli-0.1.3.tar.gz | 327.7 kB | With provenance | Details for datatool_cli-0.1.3.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| datatool_cli-0.1.3-py3-none-any.whl | Python 3 | none | any | Details for datatool_cli-0.1.3-py3-none-any.whl |
Total release size: 401.0 kB
Release files / datatool_cli-0.1.3.tar.gz
| Download URL | datatool_cli-0.1.3.tar.gz |
|---|---|
| Size | 327.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6763f06e12eec693fc55b3571d6ca5e87c1413afecac10391f48f0975e30abc5
|
|
BLAKE2b-256 checksum How to use checksums |
4d47063ed623d8f772eacfa00beb7934af9a57a1a65cd937ca921128b2f6b0dc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency logRelease files / datatool_cli-0.1.3-py3-none-any.whl
| Download URL | datatool_cli-0.1.3-py3-none-any.whl |
|---|---|
| Size | 73.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
321618311ac1a7a7d5fdeda1b70f4f5847d2ec8b2b2b70bd67259d4ffe7c6d8c
|
|
BLAKE2b-256 checksum How to use checksums |
7dee1858f89aa9766bf0d34cb9cf2f011bcd0cfac163e7916e5a933e766c043f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency logSecurity for datatool-cli 0.1.3
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for datatool_cli-0.1.3.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.