gleanwork / gleanwork/api-client-python

Model serialization drops keys

Abierto
#105 2 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Lenguaje dominante
Python
Estrellas
20
Forks
10
Merge medio
1 d 6 h
PR fusionados (30 d)
17

Descripción

There may be an issue affecting the serialize_model methods of the Pydantic models in this library.

Taking the DocumentContent model as an example, we see:

class DocumentContent(BaseModel):
    full_text_list: Annotated[
        Optional[List[str]], pydantic.Field(alias="fullTextList")
    ] = None
    r"""The plaintext content of the document."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(["fullTextList"])
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)

            if val != UNSET_SENTINEL:
                if val is not None or k not in optional_fields:
                    m[k] = val

        return m

This model uses a field alias that, when constructing the Pydantic object from an API response, will map the fullTextList field of the JSON object to the full_text_list field of the Pydantic object.

However, the model serializer uses:

...
k = f.alias or n
val = serialized.get(k)
...

which means that the field alias (fullTextList) will be used to extract the value rather than the Pydantic field name. This results in value being None and in missing keys in the returned dictionary m when the field name and its alias are different.

To support this claim, please find attached a documents.json file that contains an anonymized response collected from the Glean API (/rest/api/v1/getdocuments endpoint).

And below is a simple debug.py script to run alongside it:

import pathlib

from glean.api_client import models
from glean.api_client.utils.unmarshal_json_response import unmarshal_json_response


class DummyHttpResponse:
    def __init__(self, text):
        self.status_code = 200
        self.text = text


with pathlib.Path("documents.json").open("r") as f:
    http_res = DummyHttpResponse(
        text=f.read(),
    )


documents_response = unmarshal_json_response(models.GetDocumentsResponse, http_res)


assert isinstance(documents_response, models.GetDocumentsResponse)
assert documents_response.documents is not None
assert isinstance(
    documents_response.documents["https://company.com/Test"].content,
    models.DocumentContent,
)
assert (
    documents_response.documents["https://company.com/Test"].content.full_text_list[0]
    == "This is a test document."
)

serialized_document_response = documents_response.model_dump()

assert isinstance(serialized_document_response, dict)
assert serialized_document_response["documents"] is not None

# Here's the problem: no `full_text_list` or `fullTextList` in the serialized response!
assert (
    len(serialized_document_response["documents"]["https://company.com/Test"]["content"])
    > 0
)

Running it yields:

$ ls    
debug.py  documents.json

$ python debug.py
Traceback (most recent call last):
  File "/workspace/app/debug/debug.py", line 40, in <module>
    len(serialized_document_response["documents"]["https://company.com/Test"]["content"])
    > 0
AssertionError

Note that I'm using:

pydantic_core==2.41.5
pydantic==2.12.5
glean-api-client==0.11.27

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Línea de trabajo

Comienza con src/glean/api_client/models/documentcontent.py e inspecciona serialize_model; después ejecuta debug.py con documents.json mediante unmarshal_json_response. Se considera terminado cuando el contenido serializado de DocumentContent no está vacío e incluye el campo afectado, tal como comprueban las assertions de debug.py.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
python
Área
api
Tipo de issue
Error
Dificultad
2/5
Tiempo estimado
1-3 horas
Estado de actividad
Estancado
Claridad
Bien especificado
Aptitud para principiantes
45/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.