Skip to content

Exemplos da documentação rodam como estão escritos, e as páginas descrevem o que o código faz - #264

Merged
bdcdo merged 13 commits into
mainfrom
docs/exemplos-e-afirmacoes
Oct 29, 2026
Merged

bdcdo merged 13 commits into
mainfrom
docs/exemplos-e-afirmacoes

Conversation

@bdcdo

@bdcdo bdcdo commented Oct 22, 2026

Copy link
Copy Markdown
Owner

Problema

Três exemplos da documentação quebram ou mostram um resultado que não aconteceu, e várias páginas afirmam o que o código não faz. Rodados com o LLM trocado por dublê na main de agora:

  • docs/guides/basic-usage.md em sequência: a chamada com Categoria levanta ValueError: ... campos incompatíveis ['categoria', 'subcategoria'], porque o df já saiu processado com Sentimento; o mesmo acontece com Entidades e Resumo, e os três exemplos de providers fazem 0 chamadas ao modelo.
  • Notebook 04: as três chamadas das células 11 e 13 usam o mesmo df, e só a primeira chama o modelo; as três saídas da comparação entre prompts mostram o resultado do primeiro. Notebook 08: a célula 20 reusa o df da 13 e faz 0 chamadas.
  • docs/guides/web-search.md, "Exemplo: Trace Completo": MedicamentoInfo tem prompt e prompt_append em json_schema_extra, e a chamada sem search_per_field=True levanta ValueError antes de qualquer linha.

A causa dos dois primeiros é que o DataFrame pandas de entrada é modificado no lugar, o que nenhuma página dizia. Entre as afirmações, a mais cara é a assinatura de api.md, que omitia perguntas na 4ª posição: dataframeit(saida, M, "p", False) cai em perguntas, que é ignorado, e chama o modelo que resume=False evitaria.

O que muda

Em docs/ e docs/en/, e nos três READMEs onde o trecho está neles:

Item da issue Estado
Trace completo sem search_per_field=True Corrigido. O exemplo lê _trace, a coluna do agente único, e passa a usar EmpresaInfo / CompanyInfo, o modelo de "Uso Básico", que não tem configuração por campo. Com search_per_field=True a coluna seria _trace_{campo}, que é o exemplo "Trace por Campo", logo abaixo
Notebook 04, células 11 e 13 Corrigido: cada chamada recebe df.copy()
Notebook 08, célula 20 Corrigido: processa um DataFrame novo com os mesmos textos. df.copy() não bastaria, porque a célula 13 já gravou o status no df
basic-usage.md em sequência Corrigido: as chamadas sobre df passam df.copy(), inclusive as três de providers, e a página diz por quê
api.md não diz que a entrada é modificada no lugar Corrigido: seção "Entrada modificada no lugar", com o que fica no DataFrame, o que acontece numa segunda chamada e o que não é alterado (polars, Series, list, dict)
Ordem dos parâmetros em api.md Corrigido: a assinatura traz perguntas=None na 4ª posição, conferida contra a main de agora
"A saída volta no mesmo formato da entrada" (index.md, api.md) Corrigido: a saída é DataFrame, do polars para entrada polars e do pandas para as demais
"Uma falha numa linha não interrompe a execução" Corrigido: a frase ganha a exceção, e a seção nova "Falhas que interrompem a execução" descreve o que acontece
exceptions.md sem ProviderAbortError e ProviderUsageLimitError Corrigido: entram na árvore e na tabela
"Métricas de throughput em tempo real" Corrigido em index.md: saem no resumo final, só com parallel_requests > 1. performance.md passa a dizer o mesmo, porque o exemplo de lá mostra a seção numa chamada sem parallel_requests
Mensagem de dependência na FAQ Corrigido: a mensagem sugere pip install langchain-anthropic ou dataframeit[all]; no claude_code e no codex, o extra. A linha do ImportError em exceptions.md, que dizia o mesmo que a FAQ, também
api_key no codex e no claude_code Corrigido: o codex recusa com ProviderConfigurationError, o claude_code ignora
Extra all nos READMEs Corrigido: "os providers acima menos o Codex, mais busca web, Polars e Excel". O comentário da instalação rápida em index.md, que dizia "todos os providers", também
Tabelas de saída sem as colunas de token Corrigido no README e no início rápido: a tabela mostra as colunas do modelo, e a frase seguinte diz que a saída traz também as quatro colunas de tokens

Fica fora a afirmação de que a resposta fora do modelo volta ao LLM com o erro para correção (index.md, card "Saída Estruturada"), que é da #193.

Decisões

  • O notebook 04 também passa uma cópia de df_comentarios na célula 17. Sem ela, o erro que a célula 19 mostra lista as colunas que a 17 gravou (sentimento, _dataframeit_status, as de tokens), e o texto da célula fala do "mesmo DataFrame".
  • As demais páginas que repetem df em vários blocos (providers, performance, error-handling, web-search, llm-reference, os exemplos de api.md) ficam como estão: ali os blocos são alternativas sobre um df genérico, muitos com Model de marcador, e não uma sequência para rodar. A seção nova de api.md cobre o caso.
  • Dois testes passam a guardar a classe dos erros, para que não voltem em silêncio:
    • tests/test_exemplos.py::test_exemplo_nao_reusa_dataframe_ja_processado reprova o notebook ou script de example/ que passa a dataframeit() um DataFrame que uma chamada anterior já processou, ou uma cópia dele, sem atribuir o nome de novo no meio. O 03_resume, que relê o checkpoint antes de cada chamada, passa.
    • tests/test_api_publica.py confere que a assinatura de api.md, nas duas línguas, tem a ordem de inspect.signature(dataframeit), e que exceptions.md cita toda exceção de __all__.
  • Os notebooks continuam versionados sem saídas. A limpeza de lint deles fica para a Lint dos exemplos e dos notebooks #211.

Closes #200

bdcdo added 7 commits October 21, 2026 22:06
…cessado

O dataframeit grava os resultados e o status no próprio DataFrame pandas
que recebe. No notebook 04, as células 11 e 13 chamavam dataframeit três
vezes com o mesmo df, e só a primeira chamava o modelo; a comparação
entre prompts mostrava os resultados da primeira. No 08, a célula 20
reusava o df da célula 13 e não fazia nenhuma chamada.

O 04 passa df.copy() a cada chamada, e a célula 17 passa uma cópia de
df_comentarios, para que o erro da célula 19 liste as colunas do
DataFrame como ele foi criado. O 08 processa na célula 20 um DataFrame
novo com os mesmos textos.

test_exemplo_nao_reusa_dataframe_ja_processado reprova o notebook ou
script que passa a dataframeit() um nome já processado, ou uma cópia
dele, sem atribuí-lo de novo no meio.
…no lugar

A assinatura em api.md omitia perguntas, o 4º parâmetro de
dataframeit(). Quem passava resume por posição caía em perguntas, que é
ignorado: dataframeit(saida, M, "p", False) chamava o modelo que
resume=False evitaria. A assinatura passa a trazê-lo, e
test_assinatura_da_referencia_segue_a_ordem_do_codigo compara a ordem
documentada com a de inspect.signature nas duas línguas.

O retorno deixa de dizer que a saída volta no formato da entrada: é
DataFrame do polars para entrada polars e do pandas para as demais. A
seção nova "Entrada modificada no lugar" diz que a entrada pd.DataFrame
recebe as colunas do modelo e as de controle, inclusive o status que a
saída remove, e o que acontece numa segunda chamada sobre ela.

A página de exceções lista ProviderAbortError e ProviderUsageLimitError,
que estão em __all__, e a frase "uma falha numa linha não interrompe a
execução" ganha a exceção delas, que param o despacho das linhas
seguintes. A linha do ImportError mostra o que a mensagem pede de fato.
test_pagina_de_excecoes_lista_todas_as_exportadas reprova a exceção
exportada que a página não cita.
Rodados em sequência, os exemplos de basic-usage.md reusavam o df já
processado com Sentimento, e a chamada com Categoria levantava
ValueError por campos incompatíveis; os três exemplos de providers não
chamavam o modelo. Cada chamada passa df.copy(), e a página diz por quê.

O exemplo de trace completo em web-search.md chamava MedicamentoInfo,
que usa prompt e prompt_append em json_schema_extra, sem
search_per_field=True, e levantava ValueError. Ele lê _trace, a coluna
do agente único, e passa a usar EmpresaInfo, o modelo de Uso Básico,
que não tem configuração por campo. O trace por campo segue no exemplo
seguinte.
…o atual

- FAQ: a mensagem de dependência sugere o pacote LangChain do provider
  ou o extra all, e não dataframeit[anthropic]; o claude_code e o codex
  pedem o extra deles. Só o codex recusa api_key; o claude_code a
  ignora.
- Página inicial: as métricas de throughput saem no resumo final e só
  com parallel_requests > 1, e não em tempo real; a saída é sempre
  DataFrame, e não "no mesmo formato da entrada". Performance diz o
  mesmo sobre a seção de throughput.
- READMEs e página inicial: o comentário do extra all deixa de se ler
  como se ele excluísse busca web, Polars e Excel.
- READMEs e início rápido: a saída do exemplo também traz as colunas de
  tokens, que o padrão track_tokens=True grava.
@bdcdo

bdcdo commented Oct 22, 2026

Copy link
Copy Markdown
Owner Author

Evidência

Base: origin/main em b48bd034. Ramo: 2bfdb7eb. O ramo não toca src/ (git diff --stat origin/main...HEAD -- src sai vazio); muda 16 páginas de docs/ e docs/en/, os três READMEs, os notebooks 04 e 08, o CHANGELOG.md e dois arquivos de teste. Tudo abaixo foi rodado em 2bfdb7eb e numa árvore separada de b48bd034, com Python 3.11.14 e o pacote importado do src/ de cada árvore, conferido pelo dataframeit.__file__.

Caso na base (b48bd034)

Os exemplos rodam por um script fora do repositório, executa_trechos.py. Ele executa cada fonte num namespace novo, bloco a bloco e na ordem da página, com dataframeit.core.call_langchain e dataframeit.agent.call_agent trocados por dublês que devolvem um objeto válido do modelo e contam as chamadas, e com validate_provider_dependencies e validate_search_dependencies sem efeito. Um bloco com sufixo d roda só pelas definições, com dataframeit trocado por uma função vazia; um item =... é código executado ali, como =Model=Sentimento antes do bloco 7, que usa Model sem defini-lo. Para cada chamada a dataframeit() o relatório diz o modelo, quantas chamadas ao LLM ela fez e a exceção, se houve, cortada em 160 caracteres. Mesmo script e mesmos extras nas duas árvores:

E="--extra dev --extra all --extra search-all --extra polars --extra excel --extra codex"
uv run $E python executa_trechos.py 'docs/guides/basic-usage.md#0,1,2,3,4,5,6,=Model=Sentimento,7' 'docs/en/guides/basic-usage.md#0,1,2,3,4,5,6,=Model=Sentiment,7'
uv run $E python executa_trechos.py 'docs/guides/web-search.md#1d,5d,9' 'docs/en/guides/web-search.md#1d,5d,9'
uv run $E python executa_trechos.py example/04_custom_placeholder.ipynb example/08_rate_limiting.ipynb

Saída com as linhas impressas pelas próprias células omitidas, e o ... marcando o corte. A mensagem completa da célula 19 vem da mesma execução com o corte em 600 caracteres.

===== docs/guides/basic-usage.md#0,1,2,3,4,5,6,=Model=Sentimento,7
  [bloco 0] dataframeit(Sentimento) -> chamadas ao LLM: 3
  [bloco 1] dataframeit(Categoria) -> chamadas ao LLM: 0; ValueError: O DataFrame contém linhas processadas incompatíveis com o modelo atual: campos incompatíveis ['categoria', 'subcategoria']. ...
  [bloco 2] dataframeit(Entidades) -> chamadas ao LLM: 0; ValueError: ... campos incompatíveis ['pessoas', 'organizacoes', 'locais', 'datas']. ...
  [bloco 3] dataframeit(Resumo) -> chamadas ao LLM: 0; ValueError: ... campos incompatíveis ['resumo', 'pontos_chave', 'tema_principal']. ...
  [bloco 4] dataframeit(Sentimento) -> chamadas ao LLM: 3
  [bloco 5] dataframeit(Sentimento) -> chamadas ao LLM: 2
  [bloco 6] dataframeit(Sentimento) -> chamadas ao LLM: 2
  [bloco 7] dataframeit(Sentimento) -> chamadas ao LLM: 0
  [bloco 7] dataframeit(Sentimento) -> chamadas ao LLM: 0
  [bloco 7] dataframeit(Sentimento) -> chamadas ao LLM: 0
===== docs/en/guides/basic-usage.md#0,1,2,3,4,5,6,=Model=Sentiment,7
  (as mesmas contagens e os mesmos ValueError, com Category, Entities e Summary)
===== docs/guides/web-search.md#1d,5d,9
  [bloco 9] dataframeit(MedicamentoInfo) -> chamadas ao LLM: 0; ValueError: Campos com configuração em json_schema_extra (prompt, prompt_append, search_depth, max_results, max_search_calls) requerem search_per_field=True
===== docs/en/guides/web-search.md#1d,5d,9
  [bloco 9] dataframeit(MedicationInfo) -> chamadas ao LLM: 0; ValueError: (a mesma)
===== example/04_custom_placeholder.ipynb
  [célula 11] dataframeit(Avaliacao) -> chamadas ao LLM: 3
  [célula 11] dataframeit(Avaliacao) -> chamadas ao LLM: 0
  [célula 13] dataframeit(Avaliacao) -> chamadas ao LLM: 0
  [célula 15] dataframeit(Avaliacao) -> chamadas ao LLM: 2
  [célula 15] dataframeit(Avaliacao) -> chamadas ao LLM: 2
  [célula 17] dataframeit(Avaliacao) -> chamadas ao LLM: 2
  [célula 19] dataframeit(Avaliacao) -> chamadas ao LLM: 0; ValueError: Nenhuma coluna de texto identificada entre ('texto', 'text', 'decisao', 'content', 'content_text'). Colunas disponíveis: ['id', 'autor', 'comentario', 'sentimento', '_dataframeit_status', '_error_details', '_input_tokens', '_cached_input_tokens', '_output_tokens', '_reasoning_tokens']. Passe text_column= explicitamente.
  [célula 21] dataframeit(Avaliacao) -> chamadas ao LLM: 1
===== example/08_rate_limiting.ipynb
  [célula 13] dataframeit(AnaliseTexto) -> chamadas ao LLM: 10
  [célula 20] dataframeit(AnaliseTexto) -> chamadas ao LLM: 0

Mesmo caso no ramo (2bfdb7eb)

===== docs/guides/basic-usage.md#0,1,2,3,4,5,6,=Model=Sentimento,7
  [bloco 0] dataframeit(Sentimento) -> chamadas ao LLM: 3
  [bloco 1] dataframeit(Categoria) -> chamadas ao LLM: 3
  [bloco 2] dataframeit(Entidades) -> chamadas ao LLM: 3
  [bloco 3] dataframeit(Resumo) -> chamadas ao LLM: 3
  [bloco 4] dataframeit(Sentimento) -> chamadas ao LLM: 3
  [bloco 5] dataframeit(Sentimento) -> chamadas ao LLM: 2
  [bloco 6] dataframeit(Sentimento) -> chamadas ao LLM: 2
  [bloco 7] dataframeit(Sentimento) -> chamadas ao LLM: 3
  [bloco 7] dataframeit(Sentimento) -> chamadas ao LLM: 3
  [bloco 7] dataframeit(Sentimento) -> chamadas ao LLM: 3
===== docs/en/guides/basic-usage.md#0,1,2,3,4,5,6,=Model=Sentiment,7
  (as mesmas contagens, com Sentiment, Category, Entities e Summary)
===== docs/guides/web-search.md#1d,5d,9
  [bloco 9] dataframeit(EmpresaInfo) -> chamadas ao LLM: 3
Queries realizadas: ['Microsoft empresa']
Duração: 1.23s
Modelo: gpt-6-luna
===== docs/en/guides/web-search.md#1d,5d,9
  [bloco 9] dataframeit(CompanyInfo) -> chamadas ao LLM: 3
Queries performed: ['Microsoft empresa']
Duration: 1.23s
Model: gpt-6-luna
===== example/04_custom_placeholder.ipynb
  [célula 11] dataframeit(Avaliacao) -> chamadas ao LLM: 3
  [célula 11] dataframeit(Avaliacao) -> chamadas ao LLM: 3
  [célula 13] dataframeit(Avaliacao) -> chamadas ao LLM: 3
  [célula 15] dataframeit(Avaliacao) -> chamadas ao LLM: 2
  [célula 15] dataframeit(Avaliacao) -> chamadas ao LLM: 2
  [célula 17] dataframeit(Avaliacao) -> chamadas ao LLM: 2
  [célula 19] dataframeit(Avaliacao) -> chamadas ao LLM: 0; ValueError: Nenhuma coluna de texto identificada entre ('texto', 'text', 'decisao', 'content', 'content_text'). Colunas disponíveis: ['id', 'autor', 'comentario']. Passe text_column= explicitamente.
  [célula 21] dataframeit(Avaliacao) -> chamadas ao LLM: 1
===== example/08_rate_limiting.ipynb
  [célula 13] dataframeit(AnaliseTexto) -> chamadas ao LLM: 10
  [célula 20] dataframeit(AnaliseTexto) -> chamadas ao LLM: 10

O trace usa os valores do dublê do agente, e por isso a query e a duração são fictícias. O erro da célula 19 é o que o notebook quer mostrar, para pedir text_column; no ramo ele lista só as colunas que o texto da célula descreve. As células 15, 17 e 21 dão o mesmo número nas duas árvores.

Casos cobertos

Caso Esperado Obtido na base (b48bd034) Obtido no ramo (2bfdb7eb)
basic-usage.md em sequência, pt e en cada exemplo chama o modelo blocos 1-3: ValueError antes de qualquer chamada; os três do bloco 7: 0 chamadas 3 chamadas em cada bloco de 1 a 3 e em cada uma das três do bloco 7
web-search.md, "Exemplo: Trace Completo", pt e en roda e imprime o trace ValueError antes da primeira linha 3 chamadas; imprime queries, duração e modelo
Notebook 04, segunda chamada da célula 11 e célula 13 cada prompt chama o modelo 0 e 0 3 e 3
Notebook 04, célula 19 o erro lista as colunas do df_comentarios original lista também as 7 colunas gravadas pela célula 17 ['id', 'autor', 'comentario']
Notebook 08, célula 20 processa os 10 textos 0 chamadas 10 chamadas
Assinatura de api.md na ordem de inspect.signature, pt e en passa falha: o 4º parâmetro documentado é resume, o do código é perguntas passa
exceptions.md cita toda exceção de __all__, pt e en passa falha: faltam ProviderAbortError e ProviderUsageLimitError passa
Nenhum dos 9 notebooks e scripts de example/ passa a dataframeit() um DataFrame já processado passa nos 9 falha no 04 (['df', 'df', 'df_comentarios']) e no 08 (['df']) passa nos 9
A checagem de reuso acusa o caso certo, em 9 casos sintéticos: mesmo df, cópia de df já processado, cópia nas duas chamadas, df reatribuído no meio, coluna gravada não libera, argumento por nome, saída no mesmo nome, outro DataFrame, entrada sem nome passa passa passa
mkdocs build pt e en, como o job docs (uv run --python 3.13 --extra docs mkdocs build) saída 0, sem aviso novo saída 0, 2 avisos (seletor de língua do i18n com navigation.instant) saída 0, os mesmos 2 avisos; as 12 âncoras dos links novos existem no site gerado

As linhas de teste da tabela foram rodadas assim: na árvore da base, git checkout 2bfdb7eb -- tests/test_exemplos.py tests/test_api_publica.py e uv run $E pytest -W error tests/test_exemplos.py tests/test_api_publica.py -q, com saída 6 failed, 47 passed; no ramo, o mesmo pytest dá 53 passed.

As afirmações corrigidas descrevem o comportamento do código, que é o mesmo nas duas árvores. Outro script fora do repositório, mede_afirmacoes.py, mede cada uma com call_langchain trocado por dublê (uv run $E python mede_afirmacoes.py), e a saída sai idêntica na base e no ramo.

Afirmação corrigida e página no ramo Esperado, pelo código Obtido
A assinatura tem perguntas na 4ª posição; docs/reference/api.md:14 src/dataframeit/core.py:1044 parâmetros 1 a 5: data, questions, prompt, perguntas, resume; dataframeit(saida, M, "p", False) faz 3 chamadas, resume=False faz 0
A saída é DataFrame, do polars para entrada polars e do pandas para as demais; docs/reference/api.md:106, docs/index.md:90 to_pandas em src/dataframeit/utils.py:135; from_pandas em :292, com o ramo polars em :333 list, dict, pd.Series e pd.DataFrame dão pandas.DataFrame
A entrada pandas é modificada no lugar; docs/reference/api.md:140 src/dataframeit/utils.py:163-164 devolve o próprio DataFrame; src/dataframeit/core.py:1465-1484 devolve sem chamar o modelo quando toda linha tem status depois da chamada o df tem _dataframeit_status, _error_details e as quatro colunas de tokens; a segunda chamada sobre ele faz 0 chamadas; a Series sai inalterada
ProviderAbortError e ProviderUsageLimitError param a execução; docs/reference/exceptions.md:26, :42-43, :57-58, :62-64 classes em src/dataframeit/errors.py:67 e :76; sem retry em errors.py:813-817; capturadas em src/dataframeit/core.py:2552 (sequencial) e :2742 (paralelo); checkpoint gravado em core.py:2586-2587 e :2848-2849; aviso em core.py:1636; levantadas pelo codex em src/dataframeit/codex.py:1071 e :1132 as duas classes, com parallel_requests 1 e 2: 2 de 6 chamadas, status ['processed', None, None, None, None, None], aviso "Execução interrompida: ... 5 linha(s) ficaram sem status"
Métricas de throughput só no resumo final e só com parallel_requests > 1; docs/index.md:74, docs/guides/performance.md:160 elapsed_seconds só é gravado em src/dataframeit/core.py:2852, dentro de _process_rows_parallel, e a seção sai em core.py:1804-1810 seção presente com parallel_requests=2, ausente com 1
A mensagem de dependência sugere o pacote langchain ou dataframeit[all], e claude_code e codex sugerem o extra; docs/guides/faq.md:10-12 src/dataframeit/errors.py:329-353; extras em errors.py:175 e :183 anthropic sem o pacote: pip install langchain-anthropic e pip install dataframeit[all]; claude_code: pip install dataframeit[claude-code]
codex recusa api_key e claude_code a ignora; docs/guides/faq.md:21 src/dataframeit/codex.py:412-413; src/dataframeit/claude_code.py não lê api_key (nenhuma ocorrência no arquivo) codex: ProviderConfigurationError; claude_code: 3 linhas processadas, sem erro
O extra all cobre os providers menos o Codex, mais busca web, Polars e Excel; README.md:25, README.pt-BR.md:25, README.es.md:25, docs/index.md:101 pyproject.toml:107-118 leitura do pyproject.toml
A saída traz as quatro colunas de tokens; README.md:73, README.pt-BR.md:73, README.es.md:73, docs/getting-started/quickstart.md:87 TOKEN_COLUMNS em src/dataframeit/utils.py:58 colunas da saída: texto, sentimento, _input_tokens, _cached_input_tokens, _output_tokens, _reasoning_tokens

Testes

Execução Base (b48bd034) Ramo (2bfdb7eb)
Job unit do CI: uv run --exact --extra dev --extra all --extra search-all pytest --cov=dataframeit --cov-branch --cov-report= --cov-fail-under=0 1599 passados, 129 pulados 1621 passados, 129 pulados
Job codex do CI: uv run --exact --extra dev --extra codex pytest com as mesmas opções 1393 passados, 367 pulados 1415 passados, 367 pulados
Cobertura combinada dos dois jobs: coverage combine e coverage report 100% 100%
Todos os extras num ambiente só: uv run --exact $E pytest --cov=dataframeit --cov-branch 1760 passados, 0 pulados, 99,96% 1782 passados, 0 pulados, 99,96%
Testes novos com -W error 6 falhas e 47 passados (testes do ramo sobre a documentação e os exemplos da base) 53 passados

Os 22 testes a mais são os novos: 2 da assinatura, 2 da página de exceções, 9 da checagem de reuso nos arquivos de example/ e 9 casos sintéticos dessa checagem. Os 99,96% do ambiente único vêm de src/dataframeit/codex.py:700-701, que só o job codex cobre, e se repetem na base. Gates estáticos no ramo, como no job quality (uv run --python 3.13 $E ...), todos com saída 0: ruff format --check src tests, ruff check src tests, ty check, vulture, deptry src. O CI do PR em 2bfdb7eb está verde em todos os jobs.

Risco: o PR muda documentação, dois notebooks, o CHANGELOG.md e testes, sem tocar src/. Como mexe em docs/, o merge na main republica o site pelo docs.yml, e uma página errada vai ao ar até o próximo deploy. O teste de reuso reprova um exemplo futuro que passe a dataframeit() um DataFrame já processado sem cópia nem nova atribuição; um exemplo que precise desse reuso de propósito, como uma demonstração de resume, passa se reler o DataFrame antes da chamada, como faz o 03_resume com read_df. O teste da assinatura reprova quem mudar a assinatura de dataframeit() sem atualizar api.md nas duas línguas, e o da página de exceções reprova uma exceção nova em __all__ sem entrada em exceptions.md, que é o objetivo dos dois. Desfazer: git revert do commit de merge, que republica o site com as páginas anteriores.

SHA revisado: 2bfdb7e

bdcdo added 5 commits October 29, 2026 11:36
…pção

A seção sobre a entrada modificada no lugar dizia que uma segunda chamada
com outro modelo levanta ValueError. Isso só vale quando algum campo novo não
admite None; com campos Optional, a chamada não manda nenhuma linha ao modelo,
não avisa e devolve None em todas as linhas. O texto agora descreve os dois
casos e indica um DataFrame novo ou uma cópia feita antes da primeira chamada.

A seção sobre ProviderAbortError dizia que resume=True processa só as
pendentes. Isso vale para a entrada pandas e para a saída devolvida; a entrada
polars repetida refaz todas as linhas, a lista só retoma com checkpoint_path,
e com reprocess_columns as linhas não reprocessadas ficam processed com os
valores anteriores, que resume=True sozinho não refaz.

Refs #200
O guia dizia que rodar de novo com resume=True depois de uma interrupção
processa só as pendentes, o que não vale para toda entrada nem com
reprocess_columns. A frase dá lugar a um link para a seção de exceptions.md
que descreve cada caso.

Refs #200
O guia de busca web reusava o df já processado pelo bloco de Uso Básico.
Na sequência da página, o trace completo não fazia chamada e json.loads
recebia None, e os exemplos com MedicamentoInfo e MedicamentoRegulatorio
levantavam ValueError de campos incompatíveis. Cada chamada sobre o df
passa df.copy(), e a página remete à seção de entrada modificada no
lugar, nas duas línguas.
A frase dizia que a linha do erro e todas as seguintes ficam sem status.
No modo paralelo, as linhas já em andamento quando o erro chega terminam
e ficam com status 'processed'; sem status ficam só a linha do erro e as
ainda não despachadas. Corrigido nas duas línguas.
O bloco Usando Diferentes Providers chamava Model, que a página não
define, e levantava NameError quando a página roda em sequência. Passa
a usar Sentimento (Sentiment na versão em inglês), definido no início.
@bdcdo

bdcdo commented Oct 29, 2026

Copy link
Copy Markdown
Owner Author

Revisão independente (rodada 2)

Subagente revisor do Claude, sem ler o corpo nem os comentários do PR, sobre o SHA 2bfdb7eb contra a base b48bd034, somado aos achados abertos da primeira revisão. O PR só toca docs/, tests/ e example/; não há mudança em src/.

Corrigido em 80eb03a2 (primeira revisão):

  • docs/reference/api.md, "Entrada modificada no lugar": prometia ValueError para campo já existente; com campo Optional não há erro, 0 chamadas e None. O texto agora separa campo obrigatório (erro) de Optional (sem erro).
  • docs/reference/exceptions.md, "Falhas que interrompem a execução": resumia numa instrução o que só vale para pandas. Agora descreve pandas, polars, lista, checkpoint_path e reprocess_columns.
  • docs/guides/performance.md remete a essa seção em vez de repetir a instrução.

Corrigido em 50f3dc56 (esta rodada):

  • docs/guides/web-search.md pt e en: o "Trace Completo" passava o df que o Uso Básico já processou no lugar, sem save_trace; na sequência da página o trace fazia 0 chamadas e json.loads levantava TypeError. Os blocos 5, 11 e 12 reusavam o mesmo df e levantavam ValueError de campos incompatíveis. Toda chamada passa df.copy(), com uma frase que remete a "Entrada modificada no lugar". Prova: o script do revisor sobre a página dá ok, chamadas no trace=3, e cada bloco da página roda em sequência fazendo chamadas.
  • docs/reference/exceptions.md pt e en: "essa linha e as seguintes ficam sem status" só valia no modo sequencial. Com parallel_requests=3 a linha em andamento termina processed (4 sem status em vez de 5). O texto agora descreve os dois modos.
  • docs/guides/basic-usage.md pt e en, "Usando Diferentes Providers": usava Model, que a página não define (NameError); agora usa Sentimento/Sentiment.

Nit, descartado: o helper dataframes_reusados de tests/test_exemplos.py não acusa df.head() nem df[filtro] de um df já processado e não roda sobre docs/. Guarda example/, onde nenhum caso atual é afetado; a cobertura de docs/ fica para a #211.

Preexistente, vira issue: resume=False com outro modelo sobre um df já processado faz 0 chamadas, não avisa e grava None na coluna nova.

Preexistente, já corrigido na main: 41 falhas de test_entrada_e_saida.py com pandas 3.1.0 (c0584194).

Verificado: gates verdes; unit 1621 passed (pandas 3.0.6) e codex 1415 passed; cobertura combinada 100%; prova do vermelho com docs e exemplos revertidos (6 testes novos reprovam); 6 de 7 mutações mortas, a sobrevivente equivalente; mkdocs build saída 0; issue #200 item a item; fronteira limpa; CI 10/10 em 2bfdb7eb.

Eixos não executados: LLM real; notebooks além do 04 e do 08; abort do codex real, só lido no código.

SHA revisado: 50f3dc5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Documentação: exemplos que quebram e afirmações que o código não cumpre

1 participant