Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(python): Add [de]serialization tests #6519

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

amckinney
Copy link
Member

Problem

Users have encountered a variety of runtime issues related to our Pydantic V1 <-> V2 compatibility shim which appear whenever the user [de]serializes their Pydantic models with the SDK.

Solution

We can add simple round-trip [de]serialization tests for each of the generated models using examples (which are auto-generated if not user-specified).

Code

The tests can use a simple utility like the following:

T = TypeVar('T', bound=BaseModel)

def assert_json_serialization(value: T) -> T:
    """
    Assert that a Pydantic model instance can be serialized to JSON and back.
    
    Args:
        instance: The model instance to [de]serialize.
    
    Raises:
        pytest.fail: If serialization or deserialization fails
    """
    model_type = type(value)
    type_name = model_type.__name__

    try:
        serialized = jsonable_encoder(value)
    except Exception as e:
        pytest.fail(f"Failed to serialize {type_name} to JSON: {e}")

    try:
        deserialized = parse_obj_as(model_type, serialized)
    except Exception as e:
        pytest.fail(f"Failed to deserialize {type_name} from JSON: {e}")

    assert value == deserialized, (
        f"JSON round-trip failed for {type_name}.\n"
        f"\tOriginal: {value}\n"
        f"\tDeserialized: {deserialized}"
    )

    # Return the deserialized instance for additional assertions if needed.
    return deserialized

With this, separate test files can be generated like the following:

from seed.types.types import Node, Tree
from tests.utils.assert_json_serialization import assert_json_serialization

def test_node_serialization():
    value = Node(
        name="root",
        nodes=[
            Node(
                name="left",
            ),
            Node(
                name="right",
            ),
        ],
        trees=[
            Tree(
                nodes=[
                    Node(
                        name="left",
                    ),
                    Node(
                        name="right",
                    ),
                ],
            )
        ],
    )
    assert_json_serialization(value)

CI Matrix

With this, we can generate a lightweight GitHub workflow that runs all of the tests using the matrix of Python and Pydantic versions like so:

name: Pydantic Compatibility

on: [push]
jobs:
  compat:
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
      matrix:
        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
        pydantic-version: ['1.10.20', '2.10.6']
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
      - name: Bootstrap poetry
        run: |
          curl -sSL https://install.python-poetry.org | python - -y --version 1.5.1
      - name: Install dependencies
        run: |
          poetry install
          poetry add pydantic==${{ matrix.pydantic-version }}
      - name: Run tests
        run: |
          poetry run pytest -rP .

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

Successfully merging this pull request may close these issues.

1 participant