graphql-codegen 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. graphql_codegen/__init__.py +7 -0
  2. graphql_codegen/__main__.py +5 -0
  3. graphql_codegen/_cli/__init__.py +41 -0
  4. graphql_codegen/_cli/_graphql_config.py +291 -0
  5. graphql_codegen/_cli/_introspection.py +87 -0
  6. graphql_codegen/_cli/_introspection_graphql.py +53 -0
  7. graphql_codegen/_cli/_parsing.py +67 -0
  8. graphql_codegen/_cli/_schema_pointer.py +108 -0
  9. graphql_codegen/_cli/_source.py +68 -0
  10. graphql_codegen/_cli/_write.py +22 -0
  11. graphql_codegen/_generator/__init__.py +0 -0
  12. graphql_codegen/_generator/_annotation.py +149 -0
  13. graphql_codegen/_generator/_ast_nodes.py +235 -0
  14. graphql_codegen/_generator/_data_type.py +532 -0
  15. graphql_codegen/_generator/_document.py +108 -0
  16. graphql_codegen/_generator/_document_module.py +54 -0
  17. graphql_codegen/_generator/_imports.py +166 -0
  18. graphql_codegen/_generator/_injector.py +267 -0
  19. graphql_codegen/_generator/_merge.py +149 -0
  20. graphql_codegen/_generator/_naming.py +80 -0
  21. graphql_codegen/_generator/_operation.py +223 -0
  22. graphql_codegen/_generator/_scalar.py +76 -0
  23. graphql_codegen/_generator/_schema.py +46 -0
  24. graphql_codegen/_generator/_schema_type.py +334 -0
  25. graphql_codegen/_generator/_selection.py +246 -0
  26. graphql_codegen/_generator/_structs.py +87 -0
  27. graphql_codegen/_generator/_typed_dict.py +154 -0
  28. graphql_codegen/_generator/dotted_name.py +48 -0
  29. graphql_codegen/_generator/package.py +695 -0
  30. graphql_codegen/_generator/spelling.py +168 -0
  31. graphql_codegen/_metadata.py +11 -0
  32. graphql_codegen/_note.py +12 -0
  33. graphql_codegen/config.py +42 -0
  34. graphql_codegen/document_sibling_module.py +58 -0
  35. graphql_codegen/generate.py +19 -0
  36. graphql_codegen/package_location.py +41 -0
  37. graphql_codegen/py.typed +0 -0
  38. graphql_codegen/runtime/__init__.py +20 -0
  39. graphql_codegen/runtime/_compat.py +27 -0
  40. graphql_codegen/runtime/_literal.py +18 -0
  41. graphql_codegen/runtime/_merge.py +153 -0
  42. graphql_codegen/runtime/_prepare.py +250 -0
  43. graphql_codegen/runtime/_reflection.py +376 -0
  44. graphql_codegen/runtime/_sigil.py +11 -0
  45. graphql_codegen/runtime/_transport.py +21 -0
  46. graphql_codegen/runtime/client.py +384 -0
  47. graphql_codegen/runtime/error.py +135 -0
  48. graphql_codegen/runtime/injection.py +107 -0
  49. graphql_codegen/runtime/operation.py +135 -0
  50. graphql_codegen/scalar.py +59 -0
  51. graphql_codegen-0.1.0.dist-info/METADATA +871 -0
  52. graphql_codegen-0.1.0.dist-info/RECORD +55 -0
  53. graphql_codegen-0.1.0.dist-info/WHEEL +4 -0
  54. graphql_codegen-0.1.0.dist-info/entry_points.txt +3 -0
  55. graphql_codegen-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,135 @@
1
+ # Copied into each generated package, where this line says not to edit it.
2
+
3
+ from collections.abc import Mapping
4
+ from functools import cached_property
5
+ from json import dumps
6
+ from types import MappingProxyType
7
+ from typing import Any, Final, Generic, TypeVar, final, override
8
+
9
+ from ._literal import ExecutionErrorHandling, OperationType
10
+ from ._reflection import Convert, build_parser, build_serializer
11
+ from ._sigil import SIGIL
12
+ from .error import ExecutionError
13
+
14
+ _VARIABLES_KEY: Final = ',"variables":'
15
+ _NO_INJECTIONS: Final[Mapping[str, frozenset[tuple[str, ...]]]] = MappingProxyType(
16
+ dict[str, frozenset[tuple[str, ...]]]()
17
+ )
18
+
19
+ # Declared, since PEP 695 infers variance from every method.
20
+ # Covariant, so that an operation of one type, or its request, is also one of any type.
21
+ _Type_co = TypeVar("_Type_co", bound=OperationType, covariant=True)
22
+ # Both held by `variables_type` and taken by `__call__`.
23
+ _Variables = TypeVar("_Variables", bound=Mapping[str, object])
24
+ _Data_co = TypeVar("_Data_co", covariant=True)
25
+
26
+
27
+ @final
28
+ class Operation(Generic[_Type_co, _Variables, _Data_co]):
29
+ """A generated operation, parameterized by its type, what it sends, and what it returns, in the order things happen.
30
+
31
+ Its type is a parameter, so that clients tell operation types apart statically: a subscription client takes subscriptions only, and a merge takes operations of one type.
32
+ """
33
+
34
+ def __init__(
35
+ self,
36
+ *,
37
+ operation_type: _Type_co,
38
+ name: str,
39
+ document: str,
40
+ variables_type: type[_Variables],
41
+ injections: Mapping[str, frozenset[tuple[str, ...]]] = _NO_INJECTIONS,
42
+ data_type: type[_Data_co],
43
+ ) -> None:
44
+ """*document* has the merge sigil wherever its index in a merge goes, and *injections* the path of every object receiving each injector's value, by injector name, `()` being the variables themselves.
45
+
46
+ The key an injection writes is the injector's name, which the variables' type lacks, so that callers cannot pass it.
47
+ What crosses the wire is read off *variables_type* and *data_type* at runtime: they are the only description of it.
48
+ """
49
+ self._operation_type: Final = operation_type
50
+ self._name: Final = name
51
+ self._document: Final = document
52
+ self._variables_type: Final = variables_type
53
+ self._injections: Final = injections
54
+ self._data_type: Final = data_type
55
+
56
+ def __call__(self, variables: _Variables, /) -> "Request[_Type_co, _Data_co]":
57
+ """Return the request running this operation with *variables*, checked here, before anything runs.
58
+
59
+ Their type is already bound here, so every type checker checks them exactly, whereas from a function taking both an operation and its variables, some type checkers would infer a wider type.
60
+ """
61
+ return Request(operation=self, variables=variables, on_execution_error="raise")
62
+
63
+ @override
64
+ def __repr__(self) -> str:
65
+ # The operation, rather than its document.
66
+ return (
67
+ f"Operation(operation_type={self._operation_type!r}, name={self._name!r})"
68
+ )
69
+
70
+ @cached_property
71
+ def _data_parser(self) -> Convert | None:
72
+ """Only custom scalars with a codec and `@nonNull` fields cost anything at runtime."""
73
+ return build_parser(self._data_type, partial=False)
74
+
75
+ @cached_property
76
+ def _partial_data_parser(self) -> Convert | None:
77
+ return build_parser(self._data_type, partial=True)
78
+
79
+ @cached_property
80
+ def _variables_serializer(self) -> Convert | None:
81
+ return build_serializer(self._variables_type)
82
+
83
+ @cached_property
84
+ def _request_prefix(self) -> bytes:
85
+ """Serialized once, since the document's string escaping costs as much as the document is long."""
86
+ envelope = dumps(
87
+ {"operationName": self._name, "query": self._document.replace(SIGIL, "")}
88
+ )
89
+ return (envelope[:-1] + _VARIABLES_KEY).encode()
90
+
91
+ def _request_body(self, variables: Mapping[str, object], /) -> bytes:
92
+ # `json.dumps()`'s default separators are what make the concatenation valid JSON.
93
+ return self._request_prefix + dumps(variables).encode() + b"}"
94
+
95
+
96
+ @final
97
+ class Request(Generic[_Type_co, _Data_co]):
98
+ """An operation with the variable values its caller gives, not yet those the client injects, as a :class:`requests.Request` does not yet hold the headers its session adds.
99
+
100
+ It runs nothing: `ListBooks({"first": 10})` is a value that a client runs, synchronously or not.
101
+ """
102
+
103
+ __slots__ = ("_on_execution_error", "_operation", "_variables")
104
+
105
+ def __init__(
106
+ self,
107
+ *,
108
+ # The variables' type has served its purpose once they are checked.
109
+ operation: Operation[_Type_co, Any, _Data_co],
110
+ variables: Mapping[str, object],
111
+ on_execution_error: ExecutionErrorHandling,
112
+ ) -> None:
113
+ self._operation: Final = operation
114
+ self._variables: Final = variables
115
+ self._on_execution_error: Final = on_execution_error
116
+
117
+ @override
118
+ def __repr__(self) -> str:
119
+ return f"Request(operation={self._operation!r}, variables={self._variables!r}, on_execution_error={self._on_execution_error!r})"
120
+
121
+ def returning_error(
122
+ self,
123
+ ) -> "Request[_Type_co, _Data_co | ExecutionError[_Data_co]]":
124
+ """Return a copy of this request whose :class:`~.error.ExecutionError` a client returns in place of its data instead of raising it.
125
+
126
+ The returned error is typed by the request, and so is its :meth:`~.error.ExecutionError.parse_data`, which no `except` clause can express; a caller tells it apart from the data before use.
127
+ Every other error still raises, since it means that the request as a whole failed.
128
+
129
+ """
130
+ # A request's data type being covariant, one returning its data is one returning its data or its error.
131
+ return Request(
132
+ operation=self._operation,
133
+ variables=self._variables,
134
+ on_execution_error="return",
135
+ )
@@ -0,0 +1,59 @@
1
+ from dataclasses import dataclass
2
+ from functools import cached_property
3
+ from typing import final
4
+
5
+ from graphql_codegen._generator.dotted_name import Reference, parse_dotted_name
6
+ from graphql_codegen._note import error_note
7
+
8
+
9
+ @final
10
+ @dataclass(frozen=True, kw_only=True)
11
+ class Codec:
12
+ """The functions converting a scalar's value between JSON and Python, such as a :class:`~datetime.datetime` sent as an ISO string."""
13
+
14
+ decode: str
15
+ """The dotted name of the function converting its JSON value to its Python one."""
16
+
17
+ encode: str
18
+ """The dotted name of the function converting its Python value to its JSON one."""
19
+
20
+ def __post_init__(self) -> None:
21
+ # Parsed eagerly, so that no codec holds a dotted name it cannot use.
22
+ _ = self._decode_reference, self._encode_reference
23
+
24
+ @cached_property
25
+ def _decode_reference(self) -> Reference:
26
+ with error_note("In `decode`."):
27
+ return parse_dotted_name(self.decode)
28
+
29
+ @cached_property
30
+ def _encode_reference(self) -> Reference:
31
+ with error_note("In `encode`."):
32
+ return parse_dotted_name(self.encode)
33
+
34
+
35
+ @final
36
+ @dataclass(frozen=True, kw_only=True)
37
+ class Scalar:
38
+ """How a scalar is typed, and converted if its Python value differs from its JSON one.
39
+
40
+ Not only a custom scalar: a built-in one can be given a type of its own too, such as `ID` typed `my_app.UserId`.
41
+ """
42
+
43
+ type: str
44
+ """The dotted name of its Python type.
45
+
46
+ When :attr:`codec` is ``None``, it must describe the decoded JSON value: a builtin, such as :class:`int`, or a :class:`typing.NewType` or type alias of one, such as `my_app.Isbn = NewType("Isbn", str)`.
47
+ """
48
+
49
+ codec: Codec | None = None
50
+ """When ``None``, the value stays as JSON decodes it."""
51
+
52
+ def __post_init__(self) -> None:
53
+ # Parsed eagerly, so that no scalar holds a dotted name it cannot use.
54
+ _ = self._type_reference
55
+
56
+ @cached_property
57
+ def _type_reference(self) -> Reference:
58
+ with error_note("In `type`."):
59
+ return parse_dotted_name(self.type)