Coverage for src/lexigram/graphql/module.py: 87%

15 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-25 04:37 +0800

1"""GraphQL module for dependency injection.""" 

2 

3from __future__ import annotations 

4 

5from typing import Any 

6 

7from lexigram.contracts.graphql.protocols import GraphQLExecutorProtocol 

8from lexigram.di.module import DynamicModule, Module, module 

9 

10 

11@module() 

12class GraphQLModule(Module): 

13 """GraphQL layer (Strawberry): schema building, execution, federation, and subscriptions. 

14 

15 Call :meth:`configure` to configure and mount the GraphQL endpoint. 

16 

17 Usage:: 

18 

19 import strawberry 

20 

21 @strawberry.type 

22 class Query: 

23 @strawberry.field 

24 def hello(self) -> str: 

25 return "world" 

26 

27 @module( 

28 imports=[GraphQLModule.configure(query_class=Query)] 

29 ) 

30 class AppModule(Module): 

31 pass 

32 """ 

33 

34 @classmethod 

35 def configure( 

36 cls, 

37 config: Any | None = None, 

38 query_class: Any | None = None, 

39 mutation_class: Any | None = None, 

40 subscription_class: Any | None = None, 

41 context_factory_class: Any | None = None, 

42 ) -> DynamicModule: 

43 """Create a GraphQLModule with explicit configuration. 

44 

45 Args: 

46 config: :class:`~lexigram.graphql.config.GraphQLConfig` or ``None`` 

47 for framework defaults. 

48 query_class: Optional root Strawberry ``Query`` type. 

49 mutation_class: Optional root Strawberry ``Mutation`` type. 

50 subscription_class: Optional root Strawberry ``Subscription`` type. 

51 context_factory_class: Optional custom :class:`~lexigram.graphql.core.context.ContextFactory` 

52 subclass. When ``None``, the framework's default ``ContextFactory`` is used. 

53 Subclasses can override ``create_context()`` to attach application-specific 

54 services to the GraphQL context. 

55 

56 Returns: 

57 A :class:`~lexigram.di.module.DynamicModule` descriptor. 

58 """ 

59 from lexigram.graphql.di.provider import GraphQLProvider 

60 

61 return DynamicModule( 

62 module=cls, 

63 providers=[ 

64 GraphQLProvider( 

65 config=config, 

66 query_class=query_class, 

67 mutation_class=mutation_class, 

68 subscription_class=subscription_class, 

69 context_factory_class=context_factory_class, 

70 ) 

71 ], 

72 exports=[GraphQLExecutorProtocol], 

73 is_global=True, 

74 ) 

75 

76 @classmethod 

77 def stub(cls, config: Any = None) -> DynamicModule: 

78 """Return a no-op GraphQLModule suitable for unit testing. 

79 

80 Registers a GraphQLProvider with no schema types configured. 

81 Useful for testing application structure without a real GraphQL 

82 executor. 

83 

84 Returns: 

85 A DynamicModule with noop GraphQL configuration. 

86 """ 

87 from lexigram.graphql.di.provider import GraphQLProvider 

88 

89 return DynamicModule( 

90 module=cls, 

91 providers=[GraphQLProvider()], 

92 exports=[GraphQLExecutorProtocol], 

93 is_global=True, 

94 ) 

95 

96 

97__all__ = ["GraphQLModule"]