Skip to content

The SDK is failing to serialize objects from Pydantic classes #126

Closed
@averri

Description

@averri

What are you really trying to do?

I'm trying to run a workflow passing an object of a class that is derived from Pydantic's BaseModel.

Describe the bug

When running the workflow, the following exception happens:

Object of type SignupCreate is not JSON serializable

More details:

"  File \"C:\\Users\\alexa\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\master-control-fastapi-xNDFbqbb-py3.10\\lib\\site-packages\\temporalio\\converter.py\", line 177, in to_payloads\n    payload = converter.to_payload(value)\n", "  File \"C:\\Users\\alexa\\AppData\\Local\\pypoetry\\Cache\\virtualenvs\\master-control-fastapi-xNDFbqbb-py3.10\\lib\\site-packages\\temporalio\\converter.py\", line 425, in to_payload\n    data=json.dumps(\n", "  File \"C:\\Users\\alexa\\AppData\\Local\\Programs\\Python\\Python310\\lib\\json\\__init__.py\", line 238, in dumps\n    **kw).encode(obj)\n", "  File \"C:\\Users\\alexa\\AppData\\Local\\Programs\\Python\\Python310\\lib\\json\\encoder.py\", line 199, in encode\n    chunks = self.iterencode(o, _one_shot=True)\n", "  File \"C:\\Users\\alexa\\AppData\\Local\\Programs\\Python\\Python310\\lib\\json\\encoder.py\", line 257, in iterencode\n    return _iterencode(o, 0)\n", "  File \"C:\\Users\\alexa\\AppData\\Local\\Programs\\Python\\Python310\\lib\\json\\encoder.py\", line 179, in default\n    raise TypeError(f'Object of type {o.__class__.__name__} '\n"

Minimal Reproduction

import asyncio
from datetime import timedelta

from pydantic import constr, BaseModel, EmailStr, Extra
from temporalio import activity, workflow
from temporalio.client import Client
from temporalio.worker import Worker

UsernameField = constr(min_length=3, max_length=20, strip_whitespace=True)


# While we could use multiple parameters in the activity, Temporal strongly
# encourages using a single dataclass instead which can have fields added to it
# in a backwards-compatible way.

class SignupCreate(BaseModel, extra=Extra.forbid):
    username: UsernameField
    email: EmailStr


# Basic activity that logs and does string concatenation
@activity.defn
async def create_signup(input: SignupCreate) -> str:
    activity.logger.info("Running activity with parameter %s" % input)
    return f"signup: {input}"


# Basic workflow that logs and invokes an activity
@workflow.defn
class SignupWorkflow:
    @workflow.run
    async def run(self, signup: SignupCreate) -> str:
        workflow.logger.info("Running workflow with parameter %s" % signup)
        return await workflow.execute_activity(
            create_signup,
            signup,
            start_to_close_timeout=timedelta(seconds=10),
        )


async def main():
    # Uncomment the line below to see logging
    # logging.basicConfig(level=logging.INFO)

    # Start client
    client = await Client.connect("localhost:7233")

    # Run a worker for the workflow
    async with Worker(
            client,
            task_queue="hello-activity-task-queue",
            workflows=[SignupWorkflow],
            activities=[create_signup],
    ):
        # While the worker is running, use the client to run the workflow and
        # print out its result. Note, in many production setups, the client
        # would be in a completely separate process from the worker.
        result = await client.execute_workflow(
            SignupWorkflow.run,
            SignupCreate(username="alex", email="me@gmail.com"),
            id="hello-activity-workflow-id",
            task_queue="hello-activity-task-queue",
        )
        print(f"Result: {result}")


if __name__ == "__main__":
    asyncio.run(main())

Environment/Versions

  • OS and processor: Windows 11, Intel I9
  • Temporal Version: [e.g. 1.14.0?] and/or SDK version
    • Python SDK version 0.1b1
  • Are you using Docker or Kubernetes or building Temporal from source? Answer: I'm using Docker compose, images:
    • temporalio/ui:2.5.1
    • temporalio/auto-setup:1.17.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions