Code Generator for GraphQL Query and Fragment Data Classes
Project description
qenerate
qenerate is a pluggable code generator for GraphQL Query and Fragment Data Classes.
It works hand in hand with GraphQL clients like gql.
Clients like gql return nested untyped dictionaries as result to a query.
qenerate generated classes easily transform these nested untyped dictionaries into concrete classes.
qenerate itself is not a GraphQL client and solely focuses on generating code
for transforming untyped dictionaries into concrete types.
Installation
Releases are published on pypi.
pip install qenerate
Usage
Introspection
In a first step we must obtain the GQL schema in the form of an introspection query:
qenerate introspection http://my-gql-instance:4000/graphql > introspection.json
The introspection.json is used in a next step to map concrete types to your queries and fragments.
Code Generation
qenerate code -i introspection.json dir/to/gql/files
An introspection.json and a (nested) directory holding all your *.gql files are given.
qenerate then generates data classes for every *.gql file it encounters
while traversing the given directory.
qenerate expects that a .gql file contains exactly one query, mutation or fragment definition.
Note, that the given directory and every gql. file in it share the same scope.
I.e., within this scope fragment and query names must be unique. Further, you can
freely use any fragment within queries, as long as the fragment is defined somewhere
within the scope (directory).
Example for Single Query
Single query and its generated classes.
Example for Query using a Fragment
We define a re-usable fragment which results in the following generated re-usable data classes.
The fragment is used in a query and imported in the generated python file.
More Examples
qenerate is actively used in our qontract-reconcile project. There you can find a lot of examples on how generated classes look like in more detail.
Plugins
qenerate follows a plugin based approach. I.e., multiple code generators are supported.
Choosing a code generator is done inside the query file, e.g., the following example will
generate data classes using the pydantic_v2 plugin:
# qenerate: plugin=pydantic_v2
query {
...
}
By choosing a plugin based approach, qenerate can extent its feature set creating new plugins
while at the same time keeping existing plugins stable and fully backwards compatible.
Currently available plugins are:
- pydantic_v1 for generating Pydantic data classes
- pydantic_v2 for generating Pydantic V2 data classes
Feature Flags
qenerate leverages feature flags to configure the behavior of the generator. Feature flags are passed to
the generator via comments in your .gql definition file.
Plugin
# qenerate: plugin=<plugin-id>
This feature flag tells qenerate which plugin it should use to generate the code for the given definition.
Custom Type Mapping
You can tell qenerate to map a primitive GQL type (a.k.a. Scalar) to something that you want. This can be handy if your codebase expects other primitive datatypes like, e.g., str instead of Json or datetime. This can be especially useful for custom GQL primitives.
# qenerate: map_gql_scalar=JSON -> str
The above will tell qenerate to map the GQL JSON type to str instead of pydantic's Json. You can also map multiple types, e.g.,
# qenerate: map_gql_scalar=JSON -> str
# qenerate: map_gql_scalar=DateTime -> str
Naming Collision Strategy
# qenerate: naming_collision_strategy=[PARENT_CONTEXT | ENUMERATE]
This feature flag tells qenerate how to deal with naming collisions in classes.
In GraphQL it is easy to query the same object in a nested fashion, which results
in re-definitions of the type. We call this naming collision. A naming collision
strategy defines how to adjust recurring names to make them unique.
PARENT_CONTEXT
This is the default strategy if nothing else is specified. It uses the name of the parent node in the query as a prefix.
ENUMERATE
This strategy adds the number of occurrences of this name as a suffix.
However, in most cases it might be cleaner to define a re-usable fragment instead of relying on a collision strategy. Here are some fragment examples.
Limitations
Overlapping properties
As of now qenerate does not support operations with overlapping properties. E.g.,
fragment MyFragment on Namespace {
b {
e
f
}
}
query MyQuery {
namespaces {
a
... MyFragment
b {
c # This overlapps with properties in MyFragment
}
}
}
The above is valid GQL syntax and will merge properties defined in MyFragment and b { c } into b {c,e,f}.
However, currently qenerate will fail to deduce proper base classes for these overlapps.
Work on this is being conducted in #77.
Development
CI
CI/CD is done via Konflux
Build and Dependency Management
qenerate uses UV as build and dependency management system.
Formatting
qenerate uses ruff for code checking and formatting.
Release
- Bump the version in
pyproject.toml - Update
CHANGELOG.md - Update the
uv.lockfile viauv sync -U - Create and merge a PR
Architecture
The architecture is described in more detail in this document.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file qenerate-0.9.2.tar.gz.
File metadata
- Download URL: qenerate-0.9.2.tar.gz
- Upload date:
- Size: 17.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Red Hat Enterprise Linux","version":"9.7","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
15e1bb7d752626e2ca781fc7ddf5a75a2fe6681c13fc23fde26c5dc71fa029be
|
|
| MD5 |
4a734d16ad5b76935e810325f3f02314
|
|
| BLAKE2b-256 |
5f1e34db3f832d8e96677343456e42a197b7b4ad3ca441d76629a5b08902d838
|
File details
Details for the file qenerate-0.9.2-py3-none-any.whl.
File metadata
- Download URL: qenerate-0.9.2-py3-none-any.whl
- Upload date:
- Size: 22.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Red Hat Enterprise Linux","version":"9.7","id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
43d8fbee3259171d417a1ed12169b2153ebbff4748eee448ca4263f9aeaa7658
|
|
| MD5 |
0b358420e7a611a561007f24872683d2
|
|
| BLAKE2b-256 |
c06947c59636c2ad44bc8b8b7790e3979ec7470aa5b90dd5bf602bda2d07bcc4
|