Commit 1d37e2b
authored
feat: alias generator (#449)
* feat: add use_alias_generator setting
* fix: don't silently ship wrong aliases or unformatted code
* fix: keep fragment forward references resolvable in operation modules
A generated client whose operation spreads a fragment could not be imported
on Python 3.10, with or without `defer_model_build`:
PydanticUndefinedAnnotation: name 'UserFieldsFriends' is not defined
A fragment names its nested selections by forward reference, and an operation
that spreads it subclasses the fragment class from another module:
# fragments.py
class UserFields(BaseModel):
friends: list["UserFieldsFriends"]
# list_users.py
class ListUsersUsers(UserFields):
pass
Pydantic resolves the annotations a subclass inherits against the subclass's
own module, and `UserFieldsFriends` lives in `fragments`. On 3.11+ the
inherited `ForwardRef` evaluation is reused and this happens to work; on 3.10
it is re-evaluated and fails. `requires-python` is `>= 3.10` and the default
hatch environment pins 3.10, so this failed on the version CI runs.
With `defer_model_build` the same shape failed on every supported version,
because dropping the eager `model_rebuild()` calls removes the only thing
that ever resolved those references.
Emit the names the mixin bases need into the module that has to resolve them:
from .fragments import (
UserFields,
UserFieldsFriends, # noqa: F401
)
The `noqa` is required because the name appears only inside an inherited
annotation. Keeping the build deferred rather than restoring the eager
fragment rebuilds preserves the whole import-time win - `defer_model_build`
now measures 1.79x faster to import on a 1448-type schema, against 1.74x
before, because no fragment models are built at import.
Add `ForwardRefNamesVisitor` and `collect_class_forward_ref_names()` in
`codegen.py`; `_map_fragment_forward_refs()` and `_mixin_forward_ref_import()`
in `package.py`. `ast.unparse` drops comments, so the line is injected as raw
source through the new `prepend_code` argument of `_queue_module`. Clients
with no fragment mixin are byte-for-byte unchanged.
The suite never caught this because every `expected_client` fixture is inert:
the tests diff generated source and never import it. Add two tests that
import a generated package and validate a payload, one per path. Both fail
only on Python 3.10, which the default hatch environment provides.
* docs: record graphql-core dependency and the two import-performance settings
`enable_custom_operations` makes the generated `base_operation.py` and
`client.py` import graphql-core to build and print a query AST at runtime, so
the generated package needs it alongside pydantic and httpx. It was missing
from "Generated code dependencies" and costs roughly 25 ms of import.
`defer_model_build` and `use_alias_generator` were documented in the README
but absent from the optional-settings list in `docs/02-configuration.md`,
where every other setting lives.
Also describe the `# noqa: F401` fragment import that generated operation
modules now carry, so it does not read as a code-generation bug to anyone
running a linter over the output.
* test: cover alias_generator in the multipart_uploads=false base-model test
Now that use_alias_generator exists, extend the no-upload base-model config test
to also enable it and assert alias_generator=to_camel lands on the generated
BaseModel - exercising the base-model source-path detection for all three
config rewrites in the uploads-disabled path.
* build: require pydantic >=2.8 for use_alias_generator
`use_alias_generator` sets `alias_generator=to_camel` and omits the explicit
`Field(alias=...)` for fields whose GraphQL name `to_camel` can reconstruct.
`to_camel`'s case handling was fixed in pydantic 2.8 (pydantic/pydantic#9561);
on earlier versions it could mangle names, so the generated package would
rebuild the wrong aliases. Raise the floor to 2.8 to match.
* docs: tighten the to_camel / pydantic 2.8 floor comments
* docs: move import-performance and fragments docs out of README
* fix: don't let the BaseModel config rewrite go missing unnoticed
* docs: drop the defer_model_build aside from the fragments page
* test: consolidate the rewrite_base_model config tests
* docs: place the import-performance and fragments guides in the docs site
The use_alias_generator branch predates the docs-site refactor (#446), so it
added these two guides as flat docs/07 and docs/08 pages and linked them from a
monolithic README. Move them under docs/02-guides/ to match the current
structure and repoint the config-reference links.
* fix: satisfy ty 0.0.62 in extract_operations and shorter_results
ty 0.0.62 (stricter than the version CI ran previously) flags two spots in
existing contrib plugins: the `ast.Constant.value` union widens the list
passed to `sorted()` past `SupportsRichComparison`, and `ImportFrom.module`
is `str | None` so indexing the `dict[str, set]` of extended imports with it
is rejected. Narrow the constant to `str` and bind/guard the module name.
No behaviour change.1 parent c16dc19 commit 1d37e2b
46 files changed
Lines changed: 1731 additions & 364 deletions
File tree
- ariadne_codegen
- client_generators
- contrib
- docs
- 02-guides
- 03-reference
- tests
- main
- clients
- alias_generator
- expected_client
- base_model_options_no_upload
- client_forward_refs_shorter_results/expected_client
- client_forward_refs/expected_client
- defer_model_build/expected_client
- extended_models/expected_client
- fragment_mixin_forward_refs
- inline_fragments/expected_client
- multiple_fragments/expected_client
- shorter_results/expected_client
- performance
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
| 22 | + | |
| 23 | + | |
23 | 24 | | |
24 | 25 | | |
25 | 26 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| 26 | + | |
26 | 27 | | |
27 | 28 | | |
28 | 29 | | |
| |||
34 | 35 | | |
35 | 36 | | |
36 | 37 | | |
| 38 | + | |
37 | 39 | | |
38 | 40 | | |
39 | 41 | | |
| |||
60 | 62 | | |
61 | 63 | | |
62 | 64 | | |
| 65 | + | |
63 | 66 | | |
64 | 67 | | |
65 | 68 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | 17 | | |
19 | 18 | | |
20 | | - | |
| 19 | + | |
21 | 20 | | |
22 | 21 | | |
23 | 22 | | |
24 | 23 | | |
25 | | - | |
26 | 24 | | |
27 | 25 | | |
28 | | - | |
| 26 | + | |
29 | 27 | | |
30 | 28 | | |
31 | 29 | | |
32 | 30 | | |
33 | 31 | | |
34 | 32 | | |
35 | 33 | | |
36 | | - | |
37 | 34 | | |
38 | 35 | | |
39 | 36 | | |
| |||
56 | 53 | | |
57 | 54 | | |
58 | 55 | | |
| 56 | + | |
59 | 57 | | |
60 | 58 | | |
61 | 59 | | |
62 | 60 | | |
63 | 61 | | |
64 | 62 | | |
65 | 63 | | |
| 64 | + | |
66 | 65 | | |
67 | 66 | | |
68 | 67 | | |
| |||
91 | 90 | | |
92 | 91 | | |
93 | 92 | | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | | - | |
99 | | - | |
100 | | - | |
101 | | - | |
102 | | - | |
103 | | - | |
| 93 | + | |
| 94 | + | |
104 | 95 | | |
105 | 96 | | |
106 | 97 | | |
| |||
190 | 181 | | |
191 | 182 | | |
192 | 183 | | |
193 | | - | |
| 184 | + | |
194 | 185 | | |
195 | 186 | | |
196 | 187 | | |
| |||
0 commit comments