Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
interval: monthly
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ from .error import (
)
from .injection import OMITTED as OMITTED
from .merge import merge as merge
from .operation import Operation as Operation
from .operation import Operation as Operation, OperationRequest as OperationRequest
from .request import PreparedRequest as PreparedRequest, Request as Request
```

Expand Down
2 changes: 1 addition & 1 deletion bookshop/graphql/runtime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
)
from .injection import OMITTED as OMITTED
from .merge import merge as merge
from .operation import Operation as Operation
from .operation import Operation as Operation, OperationRequest as OperationRequest
from .request import PreparedRequest as PreparedRequest, Request as Request
50 changes: 25 additions & 25 deletions bookshop/graphql/runtime/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from .error import ExecutionError, GraphqlError, UnexpectedNullError
from .injection import _Injectors
from .operation import (
_OperationRequest,
OperationRequest,
_origin_note,
_parse_response,
_resolve_variables,
Expand All @@ -23,7 +23,7 @@

@final
class _MergedRequest[Type: OperationType, Data](Request[Type, Data]):
def __init__(self, requests: Sequence[_OperationRequest[Type, object]], /) -> None:
def __init__(self, requests: Sequence[OperationRequest[Type, object]], /) -> None:
if not requests:
raise ValueError("Cannot merge no request.")

Expand All @@ -32,7 +32,7 @@ def __init__(self, requests: Sequence[_OperationRequest[Type, object]], /) -> No

@override
def __repr__(self) -> str:
return f"merge({', '.join(map(repr, self._requests))})"
return f"{merge.__name__}({', '.join(map(repr, self._requests))})"

@override
def prepare(self, *, injectors: _Injectors | None = None) -> PreparedRequest[Data]:
Expand All @@ -47,45 +47,45 @@ def prepare(self, *, injectors: _Injectors | None = None) -> PreparedRequest[Dat
# Typed position by position up to 6 requests, as many as typeshed's `asyncio.gather()`: https://github.com/python/typeshed/blob/1ee8b928886a93b060bdafbf1e30dc0bb7c85848/stdlib/asyncio/tasks.pyi#L108-L155
@overload
def merge[Type: (Literal["query"], Literal["mutation"]), D1, D2](
first: _OperationRequest[Type, D1], second: _OperationRequest[Type, D2], /
first: OperationRequest[Type, D1], second: OperationRequest[Type, D2], /
) -> Request[Type, tuple[D1, D2]]: ...
@overload
def merge[Type: (Literal["query"], Literal["mutation"]), D1, D2, D3](
first: _OperationRequest[Type, D1],
second: _OperationRequest[Type, D2],
third: _OperationRequest[Type, D3],
first: OperationRequest[Type, D1],
second: OperationRequest[Type, D2],
third: OperationRequest[Type, D3],
/,
) -> Request[Type, tuple[D1, D2, D3]]: ...
@overload
def merge[Type: (Literal["query"], Literal["mutation"]), D1, D2, D3, D4](
first: _OperationRequest[Type, D1],
second: _OperationRequest[Type, D2],
third: _OperationRequest[Type, D3],
fourth: _OperationRequest[Type, D4],
first: OperationRequest[Type, D1],
second: OperationRequest[Type, D2],
third: OperationRequest[Type, D3],
fourth: OperationRequest[Type, D4],
/,
) -> Request[Type, tuple[D1, D2, D3, D4]]: ...
@overload
def merge[Type: (Literal["query"], Literal["mutation"]), D1, D2, D3, D4, D5](
first: _OperationRequest[Type, D1],
second: _OperationRequest[Type, D2],
third: _OperationRequest[Type, D3],
fourth: _OperationRequest[Type, D4],
fifth: _OperationRequest[Type, D5],
first: OperationRequest[Type, D1],
second: OperationRequest[Type, D2],
third: OperationRequest[Type, D3],
fourth: OperationRequest[Type, D4],
fifth: OperationRequest[Type, D5],
/,
) -> Request[Type, tuple[D1, D2, D3, D4, D5]]: ...
@overload
def merge[Type: (Literal["query"], Literal["mutation"]), D1, D2, D3, D4, D5, D6](
first: _OperationRequest[Type, D1],
second: _OperationRequest[Type, D2],
third: _OperationRequest[Type, D3],
fourth: _OperationRequest[Type, D4],
fifth: _OperationRequest[Type, D5],
sixth: _OperationRequest[Type, D6],
first: OperationRequest[Type, D1],
second: OperationRequest[Type, D2],
third: OperationRequest[Type, D3],
fourth: OperationRequest[Type, D4],
fifth: OperationRequest[Type, D5],
sixth: OperationRequest[Type, D6],
/,
) -> Request[Type, tuple[D1, D2, D3, D4, D5, D6]]: ...
@overload
def merge[Type: (Literal["query"], Literal["mutation"]), Data](
requests: Sequence[_OperationRequest[Type, Data]], /
requests: Sequence[OperationRequest[Type, Data]], /
) -> Request[Type, tuple[Data, ...]]: ...
def merge(*args: Any) -> Request[Any, Any]:
"""Return one request for several queries, or several mutations, whose data is a tuple of their data.
Expand All @@ -102,7 +102,7 @@ def merge(*args: Any) -> Request[Any, Any]:

def _prepare_merged(
operation_type: OperationType,
requests: Sequence[_OperationRequest[OperationType, object]],
requests: Sequence[OperationRequest[OperationType, object]],
/,
*,
injectors: _Injectors | None,
Expand Down Expand Up @@ -192,7 +192,7 @@ def parse(raw: bytes, /) -> tuple[object, ...]:


def _raises_execution_error(
request: _OperationRequest[OperationType, object], /
request: OperationRequest[OperationType, object], /
) -> bool:
match request._on_execution_error:
case "raise":
Expand Down
27 changes: 18 additions & 9 deletions bookshop/graphql/runtime/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,19 @@ def __init__(
self._injections: Final = injections
self._data_type: Final = data_type

def __call__(self, variables: Variables, /) -> _OperationRequest[Type, Data]:
def __call__(self, variables: Variables, /) -> OperationRequest[Type, Data]:
"""Return the request of this operation with *variables*.

A method rather than a function taking both, so every type checker checks the variables against their exact type.
"""
return _OperationRequest(
return OperationRequest(
operation=self, variables=variables, on_execution_error="raise"
)

@override
def __repr__(self) -> str:
return (
f"Operation(operation_type={self._operation_type!r}, name={self._name!r})"
)
# As the document spells it, in brackets since it is not code.
return f"<{self._operation_type} {self._name}>"

@cached_property
def _data_parser(self) -> Convert | None:
Expand Down Expand Up @@ -97,7 +96,7 @@ def _request_body(self, variables: Mapping[str, object], /) -> bytes:


@final
class _OperationRequest[Type: OperationType, Data](Request[Type, Data]):
class OperationRequest[Type: OperationType, Data](Request[Type, Data]):
def __init__(
self,
*,
Expand All @@ -106,21 +105,31 @@ def __init__(
variables: Mapping[str, object],
on_execution_error: ExecutionErrorHandling,
) -> None:
"""Private."""
super().__init__(operation_type=operation._operation_type)
self._operation: Final = operation
self._variables: Final = variables
self._on_execution_error: Final = on_execution_error

@override
def __repr__(self) -> str:
return f"Request(operation={self._operation!r}, variables={self._variables!r}, on_execution_error={self._on_execution_error!r})"
# As written: the operation called with its variables.
call = f"{self._operation._name}({self._variables!r})"

match self._on_execution_error:
case "raise":
return call
case "return":
return f"{call}.{self.returning_error.__name__}()"
case _ as never:
assert_never(never)

def returning_error(
self,
) -> _OperationRequest[Type, Data | ExecutionError[Data]]:
) -> OperationRequest[Type, Data | ExecutionError[Data]]:
"""Return a copy of this request for which `PreparedRequest.parse()` returns its `ExecutionError` instead of raising it."""
# Sound since `Data` is covariant: a request returning its data is one returning its data or its error.
return _OperationRequest(
return OperationRequest(
operation=self._operation,
variables=self._variables,
on_execution_error="return",
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ license-files = ["LICENSE"]
name = "graphql-codegen"
readme = "README.md"
requires-python = ">=3.12"
version = "0.2.0"
version = "0.2.1"

[project.optional-dependencies]
# Only reading a YAML graphql-config file needs it.
Expand Down Expand Up @@ -135,7 +135,7 @@ ignore = [
"undocumented-public-module",
"undocumented-public-nested-class",
"undocumented-public-package",
"useless-import-alias", # `X as X` is how PEP 484 marks a re-export, in any module and not only an `__init__.py`.
"useless-import-alias", # `X as X` is how PEP 484 marks a re-export, in any module and not only an `__init__.py`.
]
select = ["ALL"]

Expand Down
2 changes: 1 addition & 1 deletion src/graphql_codegen/runtime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
)
from .injection import OMITTED as OMITTED
from .merge import merge as merge
from .operation import Operation as Operation
from .operation import Operation as Operation, OperationRequest as OperationRequest
from .request import PreparedRequest as PreparedRequest, Request as Request
50 changes: 25 additions & 25 deletions src/graphql_codegen/runtime/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from .error import ExecutionError, GraphqlError, UnexpectedNullError
from .injection import _Injectors
from .operation import (
_OperationRequest,
OperationRequest,
_origin_note,
_parse_response,
_resolve_variables,
Expand All @@ -23,7 +23,7 @@

@final
class _MergedRequest[Type: OperationType, Data](Request[Type, Data]):
def __init__(self, requests: Sequence[_OperationRequest[Type, object]], /) -> None:
def __init__(self, requests: Sequence[OperationRequest[Type, object]], /) -> None:
if not requests:
raise ValueError("Cannot merge no request.")

Expand All @@ -32,7 +32,7 @@ def __init__(self, requests: Sequence[_OperationRequest[Type, object]], /) -> No

@override
def __repr__(self) -> str:
return f"merge({', '.join(map(repr, self._requests))})"
return f"{merge.__name__}({', '.join(map(repr, self._requests))})"

@override
def prepare(self, *, injectors: _Injectors | None = None) -> PreparedRequest[Data]:
Expand All @@ -47,45 +47,45 @@ def prepare(self, *, injectors: _Injectors | None = None) -> PreparedRequest[Dat
# Typed position by position up to 6 requests, as many as typeshed's `asyncio.gather()`: https://github.com/python/typeshed/blob/1ee8b928886a93b060bdafbf1e30dc0bb7c85848/stdlib/asyncio/tasks.pyi#L108-L155
@overload
def merge[Type: (Literal["query"], Literal["mutation"]), D1, D2](
first: _OperationRequest[Type, D1], second: _OperationRequest[Type, D2], /
first: OperationRequest[Type, D1], second: OperationRequest[Type, D2], /
) -> Request[Type, tuple[D1, D2]]: ...
@overload
def merge[Type: (Literal["query"], Literal["mutation"]), D1, D2, D3](
first: _OperationRequest[Type, D1],
second: _OperationRequest[Type, D2],
third: _OperationRequest[Type, D3],
first: OperationRequest[Type, D1],
second: OperationRequest[Type, D2],
third: OperationRequest[Type, D3],
/,
) -> Request[Type, tuple[D1, D2, D3]]: ...
@overload
def merge[Type: (Literal["query"], Literal["mutation"]), D1, D2, D3, D4](
first: _OperationRequest[Type, D1],
second: _OperationRequest[Type, D2],
third: _OperationRequest[Type, D3],
fourth: _OperationRequest[Type, D4],
first: OperationRequest[Type, D1],
second: OperationRequest[Type, D2],
third: OperationRequest[Type, D3],
fourth: OperationRequest[Type, D4],
/,
) -> Request[Type, tuple[D1, D2, D3, D4]]: ...
@overload
def merge[Type: (Literal["query"], Literal["mutation"]), D1, D2, D3, D4, D5](
first: _OperationRequest[Type, D1],
second: _OperationRequest[Type, D2],
third: _OperationRequest[Type, D3],
fourth: _OperationRequest[Type, D4],
fifth: _OperationRequest[Type, D5],
first: OperationRequest[Type, D1],
second: OperationRequest[Type, D2],
third: OperationRequest[Type, D3],
fourth: OperationRequest[Type, D4],
fifth: OperationRequest[Type, D5],
/,
) -> Request[Type, tuple[D1, D2, D3, D4, D5]]: ...
@overload
def merge[Type: (Literal["query"], Literal["mutation"]), D1, D2, D3, D4, D5, D6](
first: _OperationRequest[Type, D1],
second: _OperationRequest[Type, D2],
third: _OperationRequest[Type, D3],
fourth: _OperationRequest[Type, D4],
fifth: _OperationRequest[Type, D5],
sixth: _OperationRequest[Type, D6],
first: OperationRequest[Type, D1],
second: OperationRequest[Type, D2],
third: OperationRequest[Type, D3],
fourth: OperationRequest[Type, D4],
fifth: OperationRequest[Type, D5],
sixth: OperationRequest[Type, D6],
/,
) -> Request[Type, tuple[D1, D2, D3, D4, D5, D6]]: ...
@overload
def merge[Type: (Literal["query"], Literal["mutation"]), Data](
requests: Sequence[_OperationRequest[Type, Data]], /
requests: Sequence[OperationRequest[Type, Data]], /
) -> Request[Type, tuple[Data, ...]]: ...
def merge(*args: Any) -> Request[Any, Any]:
"""Return one request for several queries, or several mutations, whose data is a tuple of their data.
Expand All @@ -102,7 +102,7 @@ def merge(*args: Any) -> Request[Any, Any]:

def _prepare_merged(
operation_type: OperationType,
requests: Sequence[_OperationRequest[OperationType, object]],
requests: Sequence[OperationRequest[OperationType, object]],
/,
*,
injectors: _Injectors | None,
Expand Down Expand Up @@ -192,7 +192,7 @@ def parse(raw: bytes, /) -> tuple[object, ...]:


def _raises_execution_error(
request: _OperationRequest[OperationType, object], /
request: OperationRequest[OperationType, object], /
) -> bool:
match request._on_execution_error:
case "raise":
Expand Down
Loading