Skip to content

Commit

Permalink
Bugfix Extensions Added Twice When Custom Directives Are Present #3776 (
Browse files Browse the repository at this point in the history
#3783)

* Fix extentions added twice with user diectives

* Add RELEASE.md

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Update strawberry/schema/schema.py

* Update strawberry/schema/schema.py

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Patrick Arminio <[email protected]>
  • Loading branch information
3 people authored Feb 13, 2025
1 parent 03d8aca commit 2470164
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 6 deletions.
5 changes: 5 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Release type: patch

This release fixes an issue where extensions were being duplicated when custom directives were added to the schema. Previously, when user directives were present, extensions were being appended twice to the extension list, causing them to be executed multiple times during query processing.

The fix ensures that extensions are added only once and maintains their original order. Test cases have been added to validate this behavior and ensure extensions are executed exactly once.
11 changes: 5 additions & 6 deletions strawberry/schema/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,13 +297,12 @@ class Query:
raise ValueError(f"Invalid Schema. Errors:\n\n{formatted_errors}")

def get_extensions(self, sync: bool = False) -> list[SchemaExtension]:
extensions = []
if self.directives:
extensions = [
*self.extensions,
DirectivesExtensionSync if sync else DirectivesExtension,
]
extensions: list[type[SchemaExtension] | SchemaExtension] = []
extensions.extend(self.extensions)
if self.directives:
extensions.extend(
[DirectivesExtensionSync if sync else DirectivesExtension]
)
return [
ext if isinstance(ext, SchemaExtension) else ext(execution_context=None)
for ext in extensions
Expand Down
43 changes: 43 additions & 0 deletions tests/schema/test_get_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,46 @@ def test_returns_extension_passed_by_user_and_directives_extension_sync():
schema.get_extensions(sync=True), [MyExtension, DirectivesExtensionSync]
):
assert isinstance(ext, ext_cls)


def test_no_duplicate_extensions_with_directives():
"""Test to verify that extensions are not duplicated when directives are present.
This test initially fails with the current implementation but passes
after fixing the get_extensions method.
"""

schema = strawberry.Schema(
query=Query, extensions=[MyExtension], directives=[uppercase]
)

extensions = schema.get_extensions()

# Count how many times our extension appears
ext_count = sum(1 for e in extensions if isinstance(e, MyExtension))

# With current implementation this fails as ext_count is 2
assert ext_count == 1, f"Extension appears {ext_count} times instead of once"


def test_extension_order_preserved():
"""Test to verify that extension order is preserved while removing duplicates."""

class Extension1(SchemaExtension):
pass

class Extension2(SchemaExtension):
pass

schema = strawberry.Schema(
query=Query, extensions=[Extension1, Extension2], directives=[uppercase]
)

extensions = schema.get_extensions()
extension_types = [
type(ext)
for ext in extensions
if not isinstance(ext, (DirectivesExtension, DirectivesExtensionSync))
]

assert extension_types == [Extension1, Extension2], "Extension order not preserved"

0 comments on commit 2470164

Please sign in to comment.