Skip to content

Retomada de saída polars arredonda campo inteiro acima de 2**53 e devolve a coluna como Float64 #222

Open

Description

@bdcdo

Quando a saída polars de uma execução interrompida volta como entrada com resume=True, o campo int do modelo que já tinha valor acima de 2**53 sai arredondado, e a coluna inteira sai Float64. Nenhum erro, nenhum aviso.

from unittest.mock import patch
import warnings

from pydantic import BaseModel
import polars as pl

from dataframeit import ProviderUsageLimitError, dataframeit


def rodar(df, modelo, respostas, **opcoes):
    fila = iter(respostas)

    def llm(*args, **kwargs):
        resposta = next(fila)
        if isinstance(resposta, Exception):
            raise resposta
        return {"data": resposta, "usage": None}

    with patch("dataframeit.core.call_langchain", side_effect=llm), \
         patch("dataframeit.core.validate_provider_dependencies"), \
         warnings.catch_warnings():
        warnings.simplefilter("ignore")
        return dataframeit(df, questions=modelo, prompt="{texto}", track_tokens=False, max_retries=1, **opcoes)


class M(BaseModel):
    nota: int


GRANDE = 2**53 + 1
entrada = pl.DataFrame({"texto": ["a", "b", "c"]})
parcial = rodar(entrada, M, [{"nota": GRANDE}, ProviderUsageLimitError("cota")])
print(parcial.schema["nota"], parcial["nota"].to_list())
# Int64 [9007199254740993, None, None]

final = rodar(parcial, M, [{"nota": 7}, {"nota": 8}], resume=True)
print(final.schema["nota"], final["nota"].to_list())
# Float64 [9007199254740992.0, 7.0, 8.0]

O 9007199254740993 gravado na primeira execução vira 9007199254740992.0, e as respostas novas, 7 e 8, saem 7.0 e 8.0 num campo declarado int.

Causa

A coluna do modelo volta com nulo nas linhas pendentes. to_pandas (utils.py:158) converte o frame com data.to_pandas(), e uma coluna polars Int64 com nulo chega ao pandas como float64. O valor já entra arredondado, antes de qualquer conferência da retomada.

O #217 tirou desse caminho as colunas de entrada do usuário, que saem do frame original. A coluna do modelo não tem essa saída, porque a execução escreve nela.

Três correções pela entrada foram tentadas durante o #217, olhando só o dado: inteiro anulável do pandas (Int64), coluna object com inteiros Python e float só quando o valor cabe exato. Cada uma quebrou outro caso de retomada, e nenhuma entrou. Entre as quebras: o campo bool relido de uma coluna Int64 de 0 e 1 com nulo, o campo float sobre inteiro grande, que levantou ArrowInvalid na volta, e a coluna UInt64, que levantou OverflowError.

Proposta

Tratar só a coluna do modelo, e só quando a anotação do campo é int: ler essa coluna do frame polars de entrada como inteiros Python, em vez de passar pelo float64. A anotação diz qual tipo esperar, informação que as tentativas acima não usavam. O teste é o trecho acima, mais os casos que quebraram: campo bool sobre Int64 de 0 e 1 com nulo, campo float sobre inteiro acima de 2**53 e coluna UInt64.

Relacionada: #196, que reúne outros casos em que a retomada altera valor já gravado.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions