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

Add support for using raw Python enum types in schema #3639

Merged
merged 16 commits into from
Oct 9, 2024
Merged
25 changes: 25 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Release type: patch

This release adds support for using rwa Python enum types in your schema
patrick91 marked this conversation as resolved.
Show resolved Hide resolved
(enums that are not decorated with `@strawberry.enum`)

This is useful if you have enum types from other places in your code
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (documentation): Consider expanding on the benefits of this feature

It would be helpful to briefly explain why using raw Python enums in Strawberry schemas is beneficial. This could help users better understand the value of this update.

This is useful if you have enum types from other places in your code
that you want to use in Strawberry without modification. This feature
enhances code reusability, reduces duplication, and simplifies
integration with existing Python libraries or codebases that use enums.

that you want to use in strawberry.
i.e
```py
# somewhere.py
from enum import Enum


class AnimalKind(Enum):
AXOLOTL, CAPYBARA = range(2)


# gql/animals
from somewhere import AnimalKind


@strawberry.type
class AnimalType:
kind: AnimalKind
```
Comment on lines +9 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (documentation): Improve the code example for clarity and completeness

Consider adding the missing import strawberry statement, and complete the AnimalKind enum definition. Also, you might want to add a comment to indicate that this is two separate files.

# somewhere.py
from enum import Enum

class AnimalKind(Enum):
    AXOLOTL = 0
    CAPYBARA = 1

# gql/animals.py
import strawberry
from somewhere import AnimalKind

@strawberry.type
class AnimalType:
    kind: AnimalKind

4 changes: 2 additions & 2 deletions strawberry/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
)
from typing_extensions import Annotated, Self, get_args, get_origin

from strawberry.exceptions.not_a_strawberry_enum import NotAStrawberryEnumError
from strawberry.types.base import (
StrawberryList,
StrawberryObjectDefinition,
Expand All @@ -30,6 +29,7 @@
has_object_definition,
)
from strawberry.types.enum import EnumDefinition
from strawberry.types.enum import enum as strawberry_enum
from strawberry.types.lazy_type import LazyType
from strawberry.types.private import is_private
from strawberry.types.scalar import ScalarDefinition
Expand Down Expand Up @@ -187,7 +187,7 @@ def create_enum(self, evaled_type: Any) -> EnumDefinition:
try:
return evaled_type._enum_definition
except AttributeError:
raise NotAStrawberryEnumError(evaled_type)
erikwrede marked this conversation as resolved.
Show resolved Hide resolved
return strawberry_enum(evaled_type)._enum_definition

def create_list(self, evaled_type: Any) -> StrawberryList:
item_type, *_ = get_args(evaled_type)
Expand Down
53 changes: 33 additions & 20 deletions tests/enums/test_enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import strawberry
from strawberry.exceptions import ObjectIsNotAnEnumError
from strawberry.exceptions.not_a_strawberry_enum import NotAStrawberryEnumError
from strawberry.types.base import get_object_definition
from strawberry.types.enum import EnumDefinition


Expand Down Expand Up @@ -120,25 +120,6 @@ class IceCreamFlavour(Enum):
assert definition.values[2].description is None


@pytest.mark.raises_strawberry_exception(
NotAStrawberryEnumError, match='Enum "IceCreamFlavour" is not a Strawberry enum'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should delete the exception too :)

)
def test_raises_error_when_using_enum_not_decorated():
class IceCreamFlavour(Enum):
VANILLA = strawberry.enum_value("vanilla")
STRAWBERRY = strawberry.enum_value(
"strawberry",
description="Our favourite",
)
CHOCOLATE = "chocolate"

@strawberry.type
class Query:
flavour: IceCreamFlavour

strawberry.Schema(query=Query)


def test_can_use_enum_values():
@strawberry.enum
class TestEnum(Enum):
Expand Down Expand Up @@ -169,3 +150,35 @@ class TestEnum(IntEnum):
assert TestEnum.D.value == 4

assert [x.value for x in TestEnum.__members__.values()] == [1, 2, 3, 4]


def test_default_enum_implementation() -> None:
class Foo(Enum):
BAR = "bar"
BAZ = "baz"

@strawberry.type
class Query:
@strawberry.field
def foo(self, foo: Foo) -> Foo:
return foo

schema = strawberry.Schema(Query)
res = schema.execute_sync("{ foo(foo: BAR) }")
assert not res.errors
assert res.data
assert res.data["foo"] == "BAR"
nrbnlulu marked this conversation as resolved.
Show resolved Hide resolved


def test_default_enum_reuse() -> None:
class Foo(Enum):
BAR = "bar"
BAZ = "baz"

@strawberry.type
class SomeType:
foo: Foo
bar: Foo

definition = get_object_definition(SomeType, strict=True)
assert definition.fields[1].type is definition.fields[1].type
Loading