strawberry-graphql / strawberry

A GraphQL library for Python that leverages type annotations 🍓
https://strawberry.rocks
MIT License
4.01k stars 533 forks source link

strawberry.pydantic.experimental.type strips all staticmethods from type definition besides `from_pydantic()` and `to_pydantic()` #3601

Open bg-radai opened 2 months ago

bg-radai commented 2 months ago

When a staticmethod not named from_pydantic or to_pydantic is added to a type decorated with strawberry.pydantic.experimental.type it is not available at runtime. Attempting to call the staticmethod will result in an AttributeError.

Describe the Bug

given an example type like this:

import strawberry
from pydantic import BaseModel

class Foo(BaseModel):
    bar: int

@strawberry.experimental.pydantic.type(model=Foo)
class FooGQLType:
    bar: strawberry.auto

    @staticmethod
    def do_something() -> None:
        # impl doesn't matter
        pass

if __name__ == "__main__":
    FooGQLType.do_something()

Running this code will result in `AttributeError: type object 'FooGQLType' has no attribute 'do_something'

In the pydantic type wrapper the cls object is redefined here using dataclasses.make_dataclass(): https://github.com/strawberry-graphql/strawberry/blob/cafc388f8221781507a53f00c02d3913679ae5be/strawberry/experimental/pydantic/object_type.py#L248

The do_something method is available as an attribute on cls before this redefinition but is unavailable afterwards.

Both to_pydantic and from_pydantic are handled as special cases. If they exist on the type definition they are saved to the namespace dict before this redefinition and re-added after the fact. if they do not exist, the default definitions are supplied

System Information

Additional Context

I ran into this issue attempting to find a workaround for a question I posted in the discord titled "Conditionally override from_pydantic()"

Upvote & Fund

Fund with Polar

quinguyen-dev commented 14 hours ago

Hey, OP.

I just ran into this issue doing something similar while trying to override from_pydantic(). Were you able to find a solution to this?

Appreciate it!