Skip to content

Commit 8aa57c7

Browse files
daudlnCopilotpre-commit-ci[bot]bellini666
authored
Fix cache schema directive class to support Strawberry >= 0.326.0 (#949)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Thiago Bellini Ribeiro <hackedbellini@gmail.com>
1 parent d91ea0c commit 8aa57c7

2 files changed

Lines changed: 37 additions & 2 deletions

File tree

RELEASE.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
release type: patch
3+
---
4+
5+
Permission extensions are now fully compatible with `strawberry-graphql >= 0.326.0`, which enforces strict type uniqueness for custom schema directives during schema construction.
6+
7+
Previously, `DjangoPermissionExtension.schema_directive` created a new anonymous `AutoDirective` class on every extension instantiation without caching it on the underlying class.
8+
When the same permission extension (e.g. `IsSuperuser()`, `IsAuthenticated()`, or custom subclasses) was attached to multiple fields, Strawberry raised a `ValueError` reporting duplicate directive definitions for the same directive name.
9+
10+
The generated `AutoDirective` class is now cached on `self.__class__` via `__dict__.get()`:
11+
12+
```python
13+
@functools.cached_property
14+
def schema_directive(self) -> object:
15+
key = "__strawberry_directive_type__"
16+
directive_class = self.__class__.__dict__.get(key)
17+
18+
if directive_class is None:
19+
@schema_directive(
20+
name=self.__class__.__name__,
21+
locations=self.SCHEMA_DIRECTIVE_LOCATIONS,
22+
description=self.SCHEMA_DIRECTIVE_DESCRIPTION,
23+
repeatable=True,
24+
)
25+
class AutoDirective: ...
26+
27+
directive_class = AutoDirective
28+
setattr(self.__class__, key, directive_class)
29+
30+
return directive_class()
31+
```
32+
33+
This ensures a single, reusable schema directive type is created per extension class, eliminating duplicate directive collisions while preserving full isolation across subclasses and maintaining backward compatibility with older Strawberry versions.

strawberry_django/permissions.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ def apply(self, field: StrawberryField) -> None: # pragma: no cover
280280
@functools.cached_property
281281
def schema_directive(self) -> object:
282282
key = "__strawberry_directive_type__"
283-
directive_class = getattr(self.__class__, key, None)
283+
directive_class = self.__class__.__dict__.get(key)
284284

285285
if directive_class is None:
286286

@@ -293,6 +293,7 @@ def schema_directive(self) -> object:
293293
class AutoDirective: ...
294294

295295
directive_class = AutoDirective
296+
setattr(self.__class__, key, directive_class)
296297

297298
return directive_class()
298299

@@ -692,7 +693,7 @@ def __init__(
692693
@functools.cached_property
693694
def schema_directive(self) -> object:
694695
key = "__strawberry_directive_class__"
695-
directive_class = getattr(self.__class__, key, None)
696+
directive_class = self.__class__.__dict__.get(key)
696697

697698
if directive_class is None:
698699

@@ -713,6 +714,7 @@ class AutoDirective:
713714
)
714715

715716
directive_class = AutoDirective
717+
setattr(self.__class__, key, directive_class)
716718

717719
return directive_class(
718720
permissions=list(self.perms),

0 commit comments

Comments
 (0)