{"id":13469218,"url":"https://github.com/mirumee/ariadne-codegen","last_synced_at":"2026-03-13T13:04:42.478Z","repository":{"id":65629910,"uuid":"537454798","full_name":"mirumee/ariadne-codegen","owner":"mirumee","description":"Generate fully typed Python client for any GraphQL API from schema, queries and mutations","archived":false,"fork":false,"pushed_at":"2025-03-05T08:57:42.000Z","size":1285,"stargazers_count":320,"open_issues_count":60,"forks_count":46,"subscribers_count":16,"default_branch":"main","last_synced_at":"2025-05-08T00:13:35.107Z","etag":null,"topics":["ariadne","client","codegen","codegenerator","graphql","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mirumee.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-16T12:47:07.000Z","updated_at":"2025-05-07T09:18:56.000Z","dependencies_parsed_at":"2023-09-23T16:42:03.371Z","dependency_job_id":"45aa153d-3f76-4b1b-9667-7a4b3297bcc4","html_url":"https://github.com/mirumee/ariadne-codegen","commit_stats":{"total_commits":756,"total_committers":25,"mean_commits":30.24,"dds":"0.22751322751322756","last_synced_commit":"11bfe35bd62b2489927e0e93c6891bccc29c7f37"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mirumee%2Fariadne-codegen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mirumee%2Fariadne-codegen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mirumee%2Fariadne-codegen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mirumee%2Fariadne-codegen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mirumee","download_url":"https://codeload.github.com/mirumee/ariadne-codegen/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254169575,"owners_count":22026213,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ariadne","client","codegen","codegenerator","graphql","python"],"created_at":"2024-07-31T15:01:29.508Z","updated_at":"2026-03-13T13:04:42.466Z","avatar_url":"https://github.com/mirumee.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# Ariadne Code Generator\n\n[![Ariadne](https://ariadnegraphql.org/img/logo-horizontal-sm.png)](https://ariadnegraphql.org)\n\n[![Build Status](https://github.com/mirumee/ariadne-codegen/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/mirumee/ariadne-codegen/actions)\n\nPython code generator that takes graphql schema, queries, mutations and subscriptions and generates Python package with fully typed and asynchronous GraphQL client.\n\nIt's available as `ariadne-codegen` command and reads configuration from the `pyproject.toml` file:\n\n```\nariadne-codegen\n```\n\nIt can also be run as `python -m ariadne_codegen`.\n\n## Features\n\n- Generate pydantic models from schema types, inputs and enums.\n- Generate pydantic models for GraphQL results.\n- Generate client package with each GraphQL operation available as async method.\n\n## Installation\n\nAriadne Code Generator can be installed with pip:\n\n```\npip install ariadne-codegen\n```\n\nTo support subscriptions, default base client requires `websockets` package:\n\n```\npip install ariadne-codegen[subscriptions]\n```\n\n## Configuration\n\n`ariadne-codegen` reads configuration from `[tool.ariadne-codegen]` section in your `pyproject.toml`. You can use other configuration file with `--config` option, eg. `ariadne-codegen --config custom_file.toml`\n\nMinimal configuration for client generation:\n\n```toml\n[tool.ariadne-codegen]\nschema_path = \"schema.graphql\"\nqueries_path = \"queries.graphql\"\n```\n\nRequired settings:\n\n- `queries_path` - path to file/directory with queries (Can be optional if `enable_custom_operations` is used)\n\nOne of the following 2 parameters is required, in case of providing both of them `schema_path` is prioritized:\n\n- `schema_path` - path to file/directory with graphql schema\n- `remote_schema_url` - url to graphql server, where introspection query can be perfomed\n\nOptional settings:\n\n- `remote_schema_headers` - extra headers that are passed along with introspection query, eg. `{\"Authorization\" = \"Bearer token\"}`. To include an environment variable in a header value, prefix the variable with `$`, eg. `{\"Authorization\" = \"$AUTH_TOKEN\"}`\n- `remote_schema_verify_ssl` (defaults to `true`) - a flag that specifies wheter to verify ssl while introspecting remote schema\n- `remote_schema_timeout` (defaults to `5`) - timeout in seconds while introspecting remote schema\n- `target_package_name` (defaults to `\"graphql_client\"`) - name of generated package\n- `target_package_path` (defaults to cwd) - path where to generate package\n- `client_name` (defaults to `\"Client\"`) - name of generated client class\n- `client_file_name` (defaults to `\"client\"`) - name of file with generated client class\n- `base_client_name` (defaults to `\"AsyncBaseClient\"`) - name of base client class\n- `base_client_file_path` (defaults to `.../ariadne_codegen/client_generators/dependencies/async_base_client.py`) - path to file where `base_client_name` is defined\n- `enums_module_name` (defaults to `\"enums\"`) - name of file with generated enums models\n- `input_types_module_name` (defaults to `\"input_types\"`) - name of file with generated input types models\n- `fragments_module_name` (defaults to `\"fragments\"`) - name of file with generated fragments models\n- `include_comments` (defaults to `\"stable\"`) - option which sets content of comments included at the top of every generated file. Valid choices are: `\"none\"` (no comments), `\"timestamp\"` (comment with generation timestamp), `\"stable\"` (comment contains a message that this is a generated file)\n- `convert_to_snake_case` (defaults to `true`) - a flag that specifies whether to convert fields and arguments names to snake case\n- `include_all_inputs` (defaults to `true`) - a flag specifying whether to include all inputs defined in the schema, or only those used in supplied operations\n- `include_all_enums` (defaults to `true`) - a flag specifying whether to include all enums defined in the schema, or only those used in supplied operations\n- `async_client` (defaults to `true`) - default generated client is `async`, change this to option `false` to generate synchronous client instead\n- `opentelemetry_client` (defaults to `false`) - default base clients don't support any performance tracing. Change this option to `true` to use the base client with Open Telemetry support.\n- `files_to_include` (defaults to `[]`) - list of files which will be copied into generated package\n- `plugins` (defaults to `[]`) - list of plugins to use during generation\n- `enable_custom_operations` (defaults to `false`) - enables building custom operations. Generates additional files that contains all the classes and methods for generation.\n\nThese options control which fields are included in the GraphQL introspection query when using `remote_schema_url`.\n\n- `introspection_descriptions` (defaults to `false`) – include descriptions in the introspection result\n- `introspection_input_value_deprecation` (defaults to `false`) – include deprecation information for input values\n- `introspection_specified_by_url` (defaults to `false`) – include `specifiedByUrl` for custom scalars\n- `introspection_schema_description` (defaults to `false`) – include schema description\n- `introspection_directive_is_repeatable` (defaults to `false`) – include `isRepeatable` information for directives\n- `introspection_input_object_one_of` (defaults to `false`) – include `oneOf` information for input objects\n\n## Custom operation builder\n\nThe custom operation builder allows you to create complex GraphQL queries in a structured and intuitive way.\n\n### Example Code\n\n```python\nimport asyncio\nfrom graphql_client import Client\nfrom graphql_client.custom_fields import (\n    ProductFields,\n    ProductTranslatableContentFields,\n    ProductTranslationFields,\n    TranslatableItemConnectionFields,\n    TranslatableItemEdgeFields,\n)\nfrom graphql_client.custom_queries import Query\nfrom graphql_client.enums import LanguageCodeEnum, TranslatableKinds\n\n\nasync def get_products():\n    # Create a client instance with the specified URL and headers\n    client = Client(\n        url=\"https://saleor.cloud/graphql/\",\n        headers={\"authorization\": \"bearer ...\"},\n    )\n\n    # Build the queries\n    product_query = Query.product(id=\"...\", channel=\"channel-uk\").fields(\n        ProductFields.id,\n        ProductFields.name,\n    )\n\n    translation_query = Query.translations(kind=TranslatableKinds.PRODUCT, first=10).fields(\n        TranslatableItemConnectionFields.edges().alias(\"aliased_edges\").fields(\n            TranslatableItemEdgeFields.node.on(\n                \"ProductTranslatableContent\",\n                ProductTranslatableContentFields.id,\n                ProductTranslatableContentFields.product_id,\n                ProductTranslatableContentFields.name,\n            )\n        )\n    )\n\n    # Execute the queries with an operation name\n    response = await client.query(\n        product_query,\n        translation_query,\n        operation_name=\"get_products\",\n    )\n\n    print(response)\n\n# Run the async function\nasyncio.run(get_products())\n```\n\n### Explanation\n\n1. Building the Product Query:\n   1. The Query.product(id=\"...\", channel=\"channel-uk\") initiates a query for a product with the specified ID and channel.\n   2. .fields(ProductFields.id, ProductFields.name) specifies the fields to retrieve for the product: id and name.\n2. Building the Translation Query:\n   1. The Query.translations(kind=TranslatableKinds.PRODUCT, first=10) initiates a query for product translations.\n   2. .fields(...) specifies the fields to retrieve for the translations.\n   3. .alias(\"aliased_edges\") renames the edges field to aliased_edges.\n   4. .on(\"ProductTranslatableContent\", ...) specifies the fields to retrieve if the node is of type ProductTranslatableContent: id, product_id, and name.\n3. Executing the Queries:\n   1. The client.query(...) method is called with the built queries and an operation name \"get_products\".\n   2. This method sends the queries to the server and retrieves the response.\n\n### Example pyproject.toml configuration\n\n`Note: queries_path is optional when enable_custom_operations is set to true`\n\n```toml\n[tool.ariadne-codegen]\nschema_path = \"schema.graphql\"\ninclude_comments = \"none\"\ntarget_package_name = \"example_client\"\nenable_custom_operations = true\n```\n\n## Plugins\n\nAriadne Codegen implements a plugin system that enables further customization and fine-tuning of generated Python code. It’s documentation is available separately in the [PLUGINS.md](https://github.com/mirumee/ariadne-codegen/blob/main/PLUGINS.md) file.\n\n### Standard plugins\n\nAriadne Codegen ships with optional plugins importable from the `ariadne_codegen.contrib` package:\n\n- [`ariadne_codegen.contrib.shorter_results.ShorterResultsPlugin`](ariadne_codegen/contrib/shorter_results.py) - This plugin processes generated client methods for operations where only single top field is requested, so they return this field's value directly instead of operation's result type. For example get_user method generated for query `GetUser() { user(...) { ... }}` will return value of user field directly instead of `GetUserResult`.\n\n- [`ariadne_codegen.contrib.extract_operations.ExtractOperationsPlugin`](ariadne_codegen/contrib/extract_operations.py) - This extracts query strings from generated client's methods into separate `operations.py` module. It also modifies the generated client to import these definitions. Generated module name can be customized by adding `operations_module_name=\"custom_name\"` to the `[tool.ariadne-codegen.operations]` section in config. Eg.:\n\n    ```toml\n    [tool.ariadne-codegen]\n    ...\n    plugins = [\"ariadne_codegen.contrib.extract_operations.ExtractOperationsPlugin\"]\n\n    [tool.ariadne-codegen.extract_operations]\n    operations_module_name = \"custom_operations_module_name\"\n    ```\n\n- [`ariadne_codegen.contrib.client_forward_refs.ClientForwardRefsPlugin`](ariadne_codegen/contrib/client_forward_refs.py) - This plugin changes generated client module moving all Pydantic models imports under the `TYPE_CHECKING` condition, making them forward references. This greatly improves the import performance of the `client` module.\n\n- [`ariadne_codegen.contrib.no_reimports.NoReimportsPlugin`](ariadne_codegen/contrib/no_reimports.py) - This plugin removes content of generated `__init__.py`. This is useful in scenarios where generated plugins contain so many Pydantic models that client's eager initialization of entire package on first import is very slow.\n\n## Using generated client\n\nGenerated client can be imported from package:\n\n```py\nfrom {target_package_name}.{client_file_name} import {client_name}\n```\n\nExample with default settings:\n\n```py\nfrom graphql_client.client import Client\n```\n\n### Passing headers to client\n\nClient (with default base client), takes passed headers and attaches them to every sent request.\n\n```py\nclient = Client(\"https://example.com/graphql\", {\"Authorization\": \"Bearer token\"})\n```\n\nFor more complex scenarios, you can pass your own http client:\n\n```py\nclient = Client(http_client=CustomComplexHttpClient())\n```\n\n`CustomComplexHttpClient` needs to be an instance of `httpx.AsyncClient` for async client, or `httpx.Client` for sync.\n\n### Websockets\n\nTo handle subscriptions, default `AsyncBaseClient` uses [websockets](https://github.com/python-websockets/websockets) and implements [graphql-transport-ws](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md) subprotocol. Arguments `ws_origin` and `ws_headers` are added as headers to the handshake request and `ws_connection_init_payload` is used as payload of [ConnectionInit](https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md#connectioninit) message.\n\n### File upload\n\nDefault base client (`AsyncBaseClient` or `BaseClient`) checks if any part of `variables` dictionary is an instance of `Upload`. If at least one instance is found then client sends multipart request according to [GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec).\n\nClass `Upload` is included in generated client and can be imported from it:\n\n```py\nfrom {target_package_name} import Upload\n```\n\nBy default we use this class to represent graphql scalar `Upload`. For schema with different name for this scalar, you can still use `Upload` and default client for file uploads:\n\n```toml\n[tool.ariadne-codegen.scalars.OTHERSCALAR]\ntype = \"Upload\"\n```\n\n### Open Telemetry\n\nWhen config option `opentelemetry_client` is set to `true` then default, included base client is replaced with one that implements the opt-in Open Telemetry support. By default this support does nothing but when the `opentelemetry-api` package is installed and the `tracer` argument is provided then the client will create spans with data about performed requests.\n\nTracing arguments handled by `BaseClientOpenTelemetry`:\n\n- `tracer`: `Optional[Union[str, Tracer]] = None` - tracer object or name which will be passed to the `get_tracer` method\n- `root_context`: `Optional[Context] = None` - optional context added to root span\n- `root_span_name`: `str = \"GraphQL Operation\"` - name of root span\n\n`AsyncBaseClientOpenTelemetry` supports all arguments which `BaseClientOpenTelemetry` does, but also exposes additional arguments regarding websockets:\n\n- `ws_root_context`: `Optional[Context] = None` - optional context added to root span for websocket connection\n- `ws_root_span_name`: `str = \"GraphQL Subscription\"` - name of root span for websocket connection\n\n## Custom scalars\n\nBy default, not built-in scalars are represented as `typing.Any` in generated client.\nYou can provide information about specific scalar by adding section to `pyproject.toml`:\n\n```toml\n[tool.ariadne-codegen.scalars.{graphql scalar name}]\ntype = \"(required) python type name\"\nserialize = \"function used to serialize scalar\"\nparse = \"function used to create scalar instance from serialized form\"\n```\n\nFor each custom scalar client will use given `type` in all occurrences of `{graphql scalar name}`. If provided, `serialize` and `parse` will be used for serialization and deserialization. In result models `type` will be annotated with `BeforeValidator`, eg. `Annotated[type, BeforeValidator(parse)]`. In inputs annotation will use `PlainSerializer`, eg. `Annotated[type, PlainSerializer(serialize)]`.\nIf `type`/`serialize`/`parse` contains at least one `.` then string will be split by it's last occurrence. First part will be used as module to import from, and second part as type/method name. For example, `type = \"custom_scalars.a.ScalarA\"` will produce `from custom_scalars.a import ScalarA`.\n\n### Example with scalar mapped to built-in type\n\nIn this case scalar is mapped to built-in `str` which doesn't require custom `serialize` and `parse` methods.\n\n```toml\n[tool.ariadne-codegen.scalars.SCALARA]\ntype = \"str\"\n```\n\n### Example with type supported by pydantic\n\nIn this scenario scalar is represented as `datetime`, so it needs to be imported. Pydantic handles serialization and deserialization so custom `parse` and `serialize` is not necessary.\n\n```toml\n[tool.ariadne-codegen.scalars.DATETIME]\ntype = \"datetime.datetime\"\n```\n\n### Example with fully custom type\n\nIn this example scalar is represented as class `TypeB`. Pydantic can't handle serialization and deserialization so custom `parse` and `serialize` is necessary. To provide `type`, `parse` and `serialize` implementation we can use `files_to_include` to copy `type_b.py` file.\n\n```toml\n[tool.ariadne-codegen]\n...\nfiles_to_include = [\".../type_b.py\"]\n\n[tool.ariadne-codegen.scalars.SCALARB]\ntype = \".type_b.TypeB\"\nparse = \".type_b.parse_b\"\nserialize = \".type_b.serialize_b\"\n```\n\n```py\n# inputs.py\n\nclass TestInput(BaseModel):\n    value_b: Annotated[TypeB, PlainSerializer(serialize_b)]\n```\n\n```py\n# get_b.py\n\nclass GetB(BaseModel):\n    query_b: Annotated[TypeB, BeforeValidator(parse_b)]\n```\n\n```py\n# client.py\n\nclass Client(AsyncBaseClient):\n    async def test_mutation(self, value: TypeB) -\u003e TestMutation:\n        ...\n        variables: dict[str, object] = {\n            \"value\": serialize_b(value),\n        }\n        ...\n```\n\n## Extending generated types\n\n### Extending models with custom mixins\n\n`mixin` directive allows to extend class generated for query/mutation field with custom logic.\n`mixin` takes two required arguments:\n\n- `from` - name of a module to import from\n- `import` - name of a parent class\n\nGenerated class will use `import` as extra base class, and import will be added to the file.\n\n```py\nfrom {from} import {import}\n...\nclass OperationNameField(BaseModel, {import}):\n    ...\n```\n\nThis directive can be used along with `files_to_include` option to extend functionality of generated classes.\n\n#### Example of usage of `mixin` and `files_to_include`\n\nQuery with `mixin` directive:\n\n```gql\nquery listUsers {\n    users @mixin(from: \".mixins\", import: \"UsersMixin\") {\n        id\n    }\n}\n```\n\nPart of `pyproject.toml` with `files_to_include` (`mixins.py` contains `UsersMixin` implementation)\n\n```toml\nfiles_to_include = [\".../mixins.py\"]\n```\n\nPart of generated `list_users.py` file:\n\n```py\n...\nfrom .mixins import UsersMixin\n...\nclass ListUsersUsers(BaseModel, UsersMixin):\n    ...\n```\n\n## Multiple clients\n\nTo generate multiple different clients you can store config for each in different file, then provide path to config file by `--config` option, eg.\n\n```\nariadne-codegen --config clientA.toml\nariadne-codegen --config clientB.toml\n```\n\n## Generated code dependencies\n\nGenerated code requires:\n\n- [pydantic](https://github.com/pydantic/pydantic)\n- [httpx](https://github.com/encode/httpx)\n- [websockets](https://github.com/python-websockets/websockets) (only for default async base client)\n\nBoth `httpx` and `websockets` dependencies can be avoided by providing another base client class with `base_client_file_path` and `base_client_name` options.\n\n## Example\n\nExample with simple schema and few queries and mutations is available [here](https://github.com/mirumee/ariadne-codegen/blob/main/EXAMPLE.md).\n\n## Generating a copy of GraphSQL schema\n\nInstead of generating a client, you can generate a file with a copy of a GraphQL schema. To do this call `ariadne-codegen` with `graphqlschema` argument:\n\n```\nariadne-codegen graphqlschema\n```\n\n`graphqlschema` mode reads configuration from the same place as [`client`](#configuration) but uses only `schema_path`, `remote_schema_url`, `remote_schema_headers`, `remote_schema_verify_ssl`, `remote_schema_timeout` options to retrieve the schema and `plugins` option to load plugins.\n\nIn addition to the above, `graphqlschema` mode also accepts additional settings specific to it:\n\n### `target_file_path`\n\nA string with destination path for generated file. Must be either a Python (`.py`), or GraphQL (`.graphql` or `.gql`) file.\n\nDefaults to `schema.py`.\n\nGenerated Python file will contain:\n\n- Necessary imports\n- Type map declaration `{type_map_variable_name}: TypeMap = {...}`\n- Schema declaration `{schema_variable_name}: GraphQLSchema = GraphQLSchema(...)`\n\nGenerated GraphQL file will contain a formatted output of the `print_schema` function from the `graphql-core` package.\n\n### `schema_variable_name`\n\nA string with a name for schema variable, must be valid python identifier.\n\nDefaults to `\"schema\"`. Used only if target is a Python file.\n\n### `type_map_variable_name`\n\nA string with a name for type map variable, must be valid python identifier.\n\nDefaults to `\"type_map\"`. Used only if target is a Python file.\n\n---\n\n## Versioning policy ##\n\n`ariadne-codegen` follows a custom versioning scheme where the minor version increases for breaking changes, while the patch version increments for bug fixes, enhancements, and other non-breaking updates.\n\nSince `ariadne-codegen` has not yet reached a stable API, this approach is in place until version 1.0.0. Once the API stabilizes, the project will adopt [Semantic Versioning](https://semver.org/)..\n\n## Development\n\nFormatting and linting use [ruff](https://github.com/astral-sh/ruff). We use [Hatch](https://github.com/pypa/hatch) for local tasks:\n\n- `hatch run lint` – lint (formatting check + typecheck)\n- `hatch fmt` – auto-format code\n- `hatch test` – tests with coverage (default Python 3.10)\n- `hatch test -a -p` – tests across all supported Python versions\n- `hatch run check` – full check (format, typecheck, tests)\n\n## Contributing\n\nWe welcome all contributions to Ariadne! If you've found a bug or issue, feel free to use [GitHub issues](https://github.com/mirumee/ariadne-codegen/issues). If you have any questions or feedback, don't hesitate to catch us on [GitHub discussions](https://github.com/mirumee/ariadne/discussions/).\n\nFor guidance and instructions, please see [CONTRIBUTING.md](CONTRIBUTING.md).\n\nAlso make sure you follow [@AriadneGraphQL](https://twitter.com/AriadneGraphQL) on Twitter for latest updates, news and random musings!\n\n## **Crafted with ❤️ by [Mirumee Software](http://mirumee.com)** \u003cariadne@mirumee.com\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmirumee%2Fariadne-codegen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmirumee%2Fariadne-codegen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmirumee%2Fariadne-codegen/lists"}