Tecnologias
A stack do ddf não foi escolhida item a item por preferência. Cada peça central resolve
um problema específico do pipeline, e várias decisões só fazem sentido em conjunto. Esta
página cobre o porquê de cada uma, com mais profundidade nas que carregam uma decisão de
arquitetura real por trás, e mais direto nas que são só infraestrutura de suporte.
Polars
pl.DataFrame existe só dentro de TabelaExtraida, TabelaCurada, BancoCurado e
ContextoDeAnalise, e nenhum Gerador importa Polars (ver
Métricas como Value Objects). Isso já é meio caminho do
porquê da escolha. O resto é o que Polars faz bem dentro dessa fronteira, em quatro
frentes concretas.
A primeira é paralelismo interno via Rayon. Os Analisadores rodam fora do pool de threads
do OrquestradorParalelo de propósito: o cálculo de métrica sobre um pl.DataFrame já
paraleliza internamente via Rayon, a biblioteca de paralelismo de dados do Rust por trás do
Polars, sem precisar de nenhuma orquestração adicional em Python.
A segunda é a API lazy. Polars permite construir um plano de operações (select/filter/
cast) e só materializar o resultado quando necessário, em vez do modelo eager do pandas,
que executa cada operação imediatamente. Essa diferença de modelo de execução foi um dos
motivos reais da escolha, independente do ganho de paralelismo.
A terceira é interoperabilidade nativa com Arrow, sem cópia extra a partir do
connectorx. connectorx decodifica direto do driver do banco para o formato Arrow
(cx.read_sql(..., return_type="polars")), a peça que sustenta o paralelismo intra-tabela
fora do GIL (ver Pipeline e paralelismo). Polars é
Arrow-native: os dados chegam do connectorx sem uma camada de conversão intermediária.
Pandas é baseado em NumPy, então o mesmo caminho exigiria uma conversão Arrow → NumPy no
meio. Usar Polars aqui não é só preferência de biblioteca, é a peça que aproveita, sem
custo de conversão, uma dependência que o ddf já tem por outro motivo.
A quarta é schema e tipagem mais estritos, coerentes com o resto do projeto. Pandas tem um
index implícito, um dtype object que aceita tipos mistos sem avisar, e um histórico de
ambiguidade entre cópia e view de um DataFrame (SettingWithCopyWarning). Polars tem
schema explícito e dtypes mais estritos. Não foi o motivo original da escolha, mas combina
com a disciplina de tipagem do resto do ddf, onde os quatro tipos do pipeline são
estruturalmente distintos sob mypy --strict (ver
Testes e qualidade). Polars encaixa aqui porque o resto do projeto
já é rigoroso com tipo, não só por causa de performance.
connectorx
Biblioteca Rust que decodifica resultado de query direto para Arrow/Polars, liberando o
GIL do Python durante a decodificação (py.allow_threads). O histórico completo, incluindo os números de benchmark que
motivaram a troca, está em
Pipeline e paralelismo.
Pydantic
Todo modelo de domínio do ddf é Pydantic. Isso garante validação de dado, imutabilidade
onde faz sentido (frozen=True nas métricas, Value Objects por definição) e serialização
consistente. arbitrary_types_allowed=True é restrito às quatro classes que carregam
pl.DataFrame (TabelaExtraida, TabelaCurada, BancoCurado, ContextoDeAnalise).
Nenhum outro modelo usa essa configuração, incluindo BancoAnalisado, que é Pydantic puro.
A mesma serialização Pydantic (model_dump_json) é o que o GeradorContextoDeIA usa como
base para produzir o contexto em JSON consumido por agentes de IA.
Jinja2
Templates Jinja são o mecanismo central de dois dos três Geradores do ddf. GeradorMarkdown usa tabela.md.jinja2 e index.md.jinja2, com um
conjunto de filtros Jinja próprios (generators/markdown/_filtros.py) que formatam tipo de
dado com precisão (NUMERIC(10,2)), combinam marcadores de restrição (PK, FK → ...,
UNIQUE) e escapam célula de tabela Markdown. A lógica de formatação vive nos filtros
Python; o template só decide onde cada valor já formatado entra.
GeradorDbt vai além de dois templates (stg_tabela.sql.jinja2, readme.md.jinja2): os
macros de teste customizado (matches_format, cast_type) usam as próprias tags Jinja do
dbt-core ({% test %}, {% macro %}), lidas como texto puro pelo ddf. O Environment
Jinja do próprio ddf não conhece essas tags; só o dbt-core em runtime as interpreta.
Esses macros seguem o padrão adapter.dispatch do dbt: uma implementação por motor
(postgres__cast_type.sql, mariadb__cast_type.sql), despachada em runtime pelo adapter
dbt configurado no projeto gerado. É o mesmo padrão citado em
Extensão via plugins como o custo real de dar suporte pleno a um motor de
banco novo no GeradorDbt: não basta implementar o Extrator, é preciso também um
conjunto de templates Jinja por motor.
O ambiente Jinja do ddf é configurado com trim_blocks/lstrip_blocks/
keep_trailing_newline (controle fino de espaço em branco, necessário porque a saída é
SQL/Markdown versionado, sensível a linha em branco espúria) e autoescape=False, porque a
saída não é HTML e escapar automaticamente produziria SQL ou Markdown corrompido.
O resto da stack
psycopg2-binary/pymysql: driver nativo de cada motor, um por Extrator concreto, mesma separação de responsabilidade do resto do Extraction Context.dbutils:PooledDB, pool de conexões reaproveitado pelos dois Extratores.pyarrow: formato de troca entreconnectorxe Polars, e dependência interna do próprio Polars para operações que envolvem Arrow.click: framework de CLI que estrutura o comandoddf.questionary: prompts interativos do wizard (múltipla escolha, confirmação).colorama: cor no terminal com suporte cross-platform, incluindo Windows.pyyaml: leitura e escrita dos overrides de curadoria.dbt-core/dbt-postgres(grupodev): valida que o projeto dbt gerado roda de verdade contra um Postgres real, não só que o YAML tem a forma esperada. O lado MariaDB passa pela mesma validação, mas fora do grupodev:dbt-mysql(único adapter dbt com suporte atype: mariadb) trava emdbt-core<=1.7, incompatível com Python 3.12 e commypy>=2.1.0do próprio projeto. O teste de integração provisiona, sob demanda, um venv Python 3.11 isolado comdbt-core==1.7.19+dbt-mysql, cacheado entre execuções e nunca instalado no venv principal.mypy,ruff,pytest,testcontainers(grupodev): guard-rails de CI, detalhados em Testes e qualidade.