strawberry-graphql / strawberry

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

Annotating types using python unions #2302

Open fireteam99 opened 1 year ago

fireteam99 commented 1 year ago

Feature Request Type

Description

It seems like python (typing) union types don't work with the lazy annotations documented here: https://strawberry.rocks/docs/types/lazy. If i have two types that need to import from each other: Kennel and Pet(union of Cat and Dog) . I will get the following error if I try to do a lazy annotation on the union type.

# pets.schema
from .pet_stores.schema import PetStore

@strawberry.type
class Cat:
  pet_store: PetStore

@strawberry.type
class Dog:
  pet_store: PetStore

Pet = Union[Cat, Dog]

# pet_stores.schema
from .pets import Pet

if TYPE_CHECKING:
    from .pets.schema import Pet

@strawberry.type
class Kennel
  pet: Annotated["Pet", strawberry.lazy(".pets.schema")]

throws:

TypeError: PetStore fields cannot be resolved. Unexpected type 'typing.Union[api_graphql.dog.schema.Dog, api_graphql.cat.schema.Cat]'

As mentioned by @patrick91 you work around this issue by swapping typing's Union with strawberry.union.

# Pet = Union[Cat, Dog]
Pet = strawberry.union("Pet", (Cat, Dog))

Discord convo: https://discord.com/channels/689806334337482765/1036814233234579526/1036814233234579526

Upvote & Fund

Fund with Polar

DoctorJohn commented 1 year ago

Unions have names in graphql, that's why strawberry.union exists. It allows us to specify the unions name (Pet in your example). Unfortunately there is no way to extract the unions name from Pet = Union[Cat, Dog], since Pet is a variable and it's name is not accessible to us :)

Feel free to reopen if I missed something :)

fireteam99 commented 1 year ago

Thanks for the explanation @DoctorJohn! Would it be worth adding this to the documentation?

DoctorJohn commented 1 year ago

Good point @fireteam99, while checking the documentation I noticed that I actually missed something: We support union creation without strawberry.union by just using typing.Union. In this case the graphql union name is generated based on the types passed as union arguments. Considering this it should be possible for strawberry to support the code you posted.

Reopening the issue (sorry for closing it, didn't remember we had that feature when answering earlier).

fireteam99 commented 1 year ago

No worries thanks for re-opening!