Generate Protocol classes for GraphQL interfaces. Generates @runtime_checkable Protocol classes and a concrete _FooClient(Type) class for query builder instantiation.
| 994 | |
| 995 | @dataclass |
| 996 | class InterfaceProtocol(Handler[GraphQLInterfaceType]): |
| 997 | """Generate Protocol classes for GraphQL interfaces. |
| 998 | |
| 999 | Generates @runtime_checkable Protocol classes and a concrete |
| 1000 | _FooClient(Type) class for query builder instantiation. |
| 1001 | """ |
| 1002 | |
| 1003 | predicate: ClassVar[Predicate] = staticmethod(is_interface_type) |
| 1004 | |
| 1005 | def type_name(self, t: GraphQLInterfaceType) -> str: |
| 1006 | return t.name |
| 1007 | |
| 1008 | def render_head(self, t: GraphQLInterfaceType) -> str: |
| 1009 | return f"@runtime_checkable\nclass {t.name}(Protocol):" |
| 1010 | |
| 1011 | @joiner |
| 1012 | def render(self, t: GraphQLInterfaceType) -> Iterator[str]: |
| 1013 | # First: the Protocol class (for type annotations and isinstance checks) |
| 1014 | yield "" |
| 1015 | yield self.render_head(t) |
| 1016 | yield indent(self.render_body(t)) |
| 1017 | yield "" |
| 1018 | |
| 1019 | # Second: a concrete client class for query builder instantiation |
| 1020 | client_name = f"_{t.name}Client" |
| 1021 | yield "" |
| 1022 | yield "@typecheck" |
| 1023 | yield f"class {client_name}(Type):" |
| 1024 | yield indent(f'"""Concrete client for {t.name} interface."""') |
| 1025 | yield "" |
| 1026 | # Override _graphql_name to return the interface name |
| 1027 | yield indent("@classmethod") |
| 1028 | yield indent("def _graphql_name(cls) -> str:") |
| 1029 | yield indent(indent(f'return "{t.name}"')) |
| 1030 | |
| 1031 | # Generate method implementations using the Object handler's field rendering |
| 1032 | for name, ifield in sorted(t.fields.items()): |
| 1033 | obj_field = _ObjectField(self.ctx, name, ifield, t) |
| 1034 | yield indent(str(obj_field)) |
| 1035 | |
| 1036 | yield "" |
| 1037 | |
| 1038 | @joiner |
| 1039 | def render_body(self, t: GraphQLInterfaceType) -> Iterator[str]: |
| 1040 | if t.description: |
| 1041 | yield from wrap(doc(t.description)) |
| 1042 | |
| 1043 | for name, ifield in sorted(t.fields.items()): |
| 1044 | if name == "id": |
| 1045 | # id is available on all Type objects |
| 1046 | continue |
| 1047 | |
| 1048 | obj_field = _ObjectField(self.ctx, name, ifield, t) |
| 1049 | sig = obj_field.func_signature() |
| 1050 | yield "" |
| 1051 | yield f"{sig}" |
| 1052 | if obj_field.description: |
| 1053 | yield indent(doc(obj_field.description)) |